mirror of
https://github.com/jbeder/yaml-cpp.git
synced 2025-09-08 20:31:17 +00:00
Reintegrated the event-api branch (second iteration) into the rtweeks21-staging branch.
This commit is contained in:
38
include/aliasmanager.h
Normal file
38
include/aliasmanager.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#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
|
14
include/anchor.h
Normal file
14
include/anchor.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#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
|
43
include/emitfromevents.h
Normal file
43
include/emitfromevents.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#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
|
34
include/eventhandler.h
Normal file
34
include/eventhandler.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#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
|
||||
|
117
include/graphbuilder.h
Normal file
117
include/graphbuilder.h
Normal file
@@ -0,0 +1,117 @@
|
||||
#ifndef GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
struct Mark;
|
||||
|
||||
// GraphBuilderInterface
|
||||
// . Abstraction of node creation
|
||||
// . pParentNode is always NULL or the return value of one of the NewXXX()
|
||||
// functions.
|
||||
class GraphBuilderInterface
|
||||
{
|
||||
public:
|
||||
// Create and return a new node with a null value.
|
||||
virtual void *NewNull(const std::string& tag, void *pParentNode) = 0;
|
||||
|
||||
// Create and return a new node with the given tag and value.
|
||||
virtual void *NewScalar(const Mark& mark, const std::string& tag, void *pParentNode, const std::string& value) = 0;
|
||||
|
||||
// Create and return a new sequence node
|
||||
virtual void *NewSequence(const Mark& mark, const std::string& tag, void *pParentNode) = 0;
|
||||
// Add pNode to pSequence. pNode was created with one of the NewXxx()
|
||||
// functions and pSequence with NewSequence().
|
||||
virtual void AppendToSequence(void *pSequence, void *pNode) = 0;
|
||||
// Note that no moew entries will be added to pSequence
|
||||
virtual void SequenceComplete(void *pSequence) {(void)pSequence;}
|
||||
|
||||
// Create and return a new map node
|
||||
virtual void *NewMap(const Mark& mark, const std::string& tag, void *pParentNode) = 0;
|
||||
// Add the pKeyNode => pValueNode mapping to pMap. pKeyNode and pValueNode
|
||||
// were created with one of the NewXxx() methods and pMap with NewMap().
|
||||
virtual void AssignInMap(void *pMap, void *pKeyNode, void *pValueNode) = 0;
|
||||
// Note that no more assignments will be made in pMap
|
||||
virtual void MapComplete(void *pMap) {(void)pMap;}
|
||||
|
||||
// Return the node that should be used in place of an alias referencing
|
||||
// pNode (pNode by default)
|
||||
virtual void *AnchorReference(const Mark& mark, void *pNode) {(void)mark; return pNode;}
|
||||
};
|
||||
|
||||
// Typesafe wrapper for GraphBuilderInterface. Assumes that Impl defines
|
||||
// Node, Sequence, and Map types. Sequence and Map must derive from Node
|
||||
// (unless Node is defined as void). Impl must also implement function with
|
||||
// all of the same names as the virtual functions in GraphBuilderInterface
|
||||
// -- including the ones with default implementations -- but with the
|
||||
// prototypes changed to accept an explicit Node*, Sequence*, or Map* where
|
||||
// appropriate.
|
||||
template <class Impl>
|
||||
class GraphBuilder : public GraphBuilderInterface
|
||||
{
|
||||
public:
|
||||
typedef typename Impl::Node Node;
|
||||
typedef typename Impl::Sequence Sequence;
|
||||
typedef typename Impl::Map Map;
|
||||
|
||||
GraphBuilder(Impl& impl) : m_impl(impl)
|
||||
{
|
||||
Map* pMap = NULL;
|
||||
Sequence* pSeq = NULL;
|
||||
Node* pNode = NULL;
|
||||
|
||||
// Type consistency checks
|
||||
pNode = pMap;
|
||||
pNode = pSeq;
|
||||
}
|
||||
|
||||
GraphBuilderInterface& AsBuilderInterface() {return *this;}
|
||||
|
||||
virtual void *NewNull(const std::string& tag, void* pParentNode) {
|
||||
return CheckType<Node>(m_impl.NewNull(tag, AsNode(pParentNode)));
|
||||
}
|
||||
|
||||
virtual void *NewScalar(const Mark& mark, const std::string& tag, void *pParentNode, const std::string& value) {
|
||||
return CheckType<Node>(m_impl.NewScalar(mark, tag, AsNode(pParentNode), value));
|
||||
}
|
||||
|
||||
virtual void *NewSequence(const Mark& mark, const std::string& tag, void *pParentNode) {
|
||||
return CheckType<Sequence>(m_impl.NewSequence(mark, tag, AsNode(pParentNode)));
|
||||
}
|
||||
virtual void AppendToSequence(void *pSequence, void *pNode) {
|
||||
m_impl.AppendToSequence(AsSequence(pSequence), AsNode(pNode));
|
||||
}
|
||||
virtual void SequenceComplete(void *pSequence) {
|
||||
m_impl.SequenceComplete(AsSequence(pSequence));
|
||||
}
|
||||
|
||||
virtual void *NewMap(const Mark& mark, const std::string& tag, void *pParentNode) {
|
||||
return CheckType<Map>(m_impl.NewMap(mark, tag, AsNode(pParentNode)));
|
||||
}
|
||||
virtual void AssignInMap(void *pMap, void *pKeyNode, void *pValueNode) {
|
||||
m_impl.AssignInMap(AsMap(pMap), AsNode(pKeyNode), AsNode(pValueNode));
|
||||
}
|
||||
virtual void MapComplete(void *pMap) {
|
||||
m_impl.MapComplete(AsMap(pMap));
|
||||
}
|
||||
|
||||
virtual void *AnchorReference(const Mark& mark, void *pNode) {
|
||||
return CheckType<Node>(m_impl.AnchorReference(mark, AsNode(pNode)));
|
||||
}
|
||||
|
||||
private:
|
||||
Impl& m_impl;
|
||||
|
||||
// Static check for pointer to T
|
||||
template <class T, class U>
|
||||
static T* CheckType(U* p) {return p;}
|
||||
|
||||
static Node *AsNode(void *pNode) {return static_cast<Node*>(pNode);}
|
||||
static Sequence *AsSequence(void *pSeq) {return static_cast<Sequence*>(pSeq);}
|
||||
static Map *AsMap(void *pMap) {return static_cast<Map*>(pMap);}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
@@ -17,10 +17,12 @@
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
class AliasManager;
|
||||
class Content;
|
||||
class Scanner;
|
||||
class Emitter;
|
||||
struct ParserState;
|
||||
class EventHandler;
|
||||
struct NodeProperties;
|
||||
|
||||
enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP };
|
||||
|
||||
@@ -32,7 +34,16 @@ namespace YAML
|
||||
|
||||
void Clear();
|
||||
std::auto_ptr<Node> Clone() const;
|
||||
void Parse(Scanner *pScanner, ParserState& state);
|
||||
void EmitEvents(EventHandler& eventHandler) const;
|
||||
void EmitEvents(AliasManager& am, EventHandler& eventHandler) 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;
|
||||
|
||||
@@ -97,19 +108,10 @@ namespace YAML
|
||||
|
||||
template <typename T>
|
||||
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:
|
||||
Mark m_mark;
|
||||
std::string m_anchor, m_tag;
|
||||
std::string m_tag;
|
||||
Content *m_pContent;
|
||||
bool m_alias;
|
||||
const Node *m_pIdentity;
|
||||
|
14
include/nodeproperties.h
Normal file
14
include/nodeproperties.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#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,20 @@
|
||||
#define PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
|
||||
#include "node.h"
|
||||
#include "graphbuilder.h"
|
||||
#include "noncopyable.h"
|
||||
#include <ios>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
class Scanner;
|
||||
struct ParserState;
|
||||
struct Directives;
|
||||
struct Mark;
|
||||
struct Token;
|
||||
class EventHandler;
|
||||
class GraphBuilderInterface;
|
||||
class Node;
|
||||
class Scanner;
|
||||
|
||||
class Parser: private noncopyable
|
||||
{
|
||||
@@ -28,6 +29,18 @@ namespace YAML
|
||||
operator bool() const;
|
||||
|
||||
void Load(std::istream& in);
|
||||
bool HandleNextDocument(EventHandler& eventHandler);
|
||||
|
||||
void *BuildNextDocumentGraph(GraphBuilderInterface& graphBuilder);
|
||||
template <class Builder>
|
||||
typename Builder::Node *BuildNextDocumentGraph(Builder& graphBuilder)
|
||||
{
|
||||
GraphBuilder<Builder> wrapper(graphBuilder); // Must be lvalue to make C++ happy
|
||||
return static_cast<typename Builder::Node *>(
|
||||
BuildNextDocumentGraph(wrapper.AsBuilderInterface())
|
||||
);
|
||||
}
|
||||
|
||||
bool GetNextDocument(Node& document);
|
||||
void PrintTokens(std::ostream& out);
|
||||
|
||||
@@ -36,10 +49,10 @@ namespace YAML
|
||||
void HandleDirective(const Token& token);
|
||||
void HandleYamlDirective(const Token& token);
|
||||
void HandleTagDirective(const Token& token);
|
||||
|
||||
|
||||
private:
|
||||
std::auto_ptr<Scanner> m_pScanner;
|
||||
std::auto_ptr<ParserState> m_pState;
|
||||
std::auto_ptr<Directives> m_pDirectives;
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -2,25 +2,10 @@
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
AliasContent::AliasContent(Content* pNodeContent)
|
||||
: m_pRef(pNodeContent)
|
||||
AliasContent::AliasContent(Content* 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
|
||||
{
|
||||
return m_pRef->GetBegin(i);
|
||||
@@ -71,6 +56,11 @@ namespace YAML
|
||||
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)
|
||||
{
|
||||
return m_pRef->Compare(pContent);
|
||||
|
@@ -12,11 +12,6 @@ namespace YAML
|
||||
{
|
||||
public:
|
||||
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::map <Node *, Node *, ltnode>::const_iterator&) const;
|
||||
@@ -29,6 +24,7 @@ namespace YAML
|
||||
virtual bool IsSequence() 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(Scalar *);
|
||||
|
45
src/aliasmanager.cpp
Normal file
45
src/aliasmanager.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
#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;
|
||||
}
|
||||
}
|
33
src/collectionstack.h
Normal file
33
src/collectionstack.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#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
|
21
src/content.cpp
Normal file
21
src/content.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#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 @@
|
||||
#define CONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include "parserstate.h"
|
||||
#include "anchor.h"
|
||||
#include "exceptions.h"
|
||||
#include "ltnode.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
class Scanner;
|
||||
class Parser;
|
||||
struct Mark;
|
||||
struct NodeProperties;
|
||||
class AliasManager;
|
||||
class EventHandler;
|
||||
class Map;
|
||||
class Node;
|
||||
class Scalar;
|
||||
class Scanner;
|
||||
class Sequence;
|
||||
class Map;
|
||||
class Emitter;
|
||||
|
||||
class Content
|
||||
{
|
||||
public:
|
||||
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::map <Node *, Node *, ltnode>::const_iterator&) const { return false; }
|
||||
@@ -40,6 +38,11 @@ namespace YAML
|
||||
virtual bool IsScalar() const { return false; }
|
||||
virtual bool IsMap() 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
|
||||
virtual bool GetScalar(std::string&) const { return false; }
|
||||
|
@@ -1,16 +1,16 @@
|
||||
#include "parserstate.h"
|
||||
#include "directives.h"
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
ParserState::ParserState()
|
||||
Directives::Directives()
|
||||
{
|
||||
// version
|
||||
version.isDefault = true;
|
||||
version.major = 1;
|
||||
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);
|
||||
if(it == tags.end()) {
|
||||
@@ -18,7 +18,7 @@ namespace YAML
|
||||
return "tag:yaml.org,2002:";
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
return it->second;
|
||||
}
|
||||
}
|
27
src/directives.h
Normal file
27
src/directives.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#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
|
106
src/emitfromevents.cpp
Normal file
106
src/emitfromevents.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
#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));
|
||||
}
|
||||
}
|
96
src/graphbuilderadapter.cpp
Normal file
96
src/graphbuilderadapter.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
#include "graphbuilderadapter.h"
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
int GraphBuilderAdapter::ContainerFrame::sequenceMarker;
|
||||
|
||||
void GraphBuilderAdapter::OnNull(const std::string& tag, anchor_t anchor)
|
||||
{
|
||||
void *pParent = GetCurrentParent();
|
||||
void *pNode = m_builder.NewNull(tag, pParent);
|
||||
RegisterAnchor(anchor, pNode);
|
||||
|
||||
DispositionNode(pNode);
|
||||
}
|
||||
|
||||
void GraphBuilderAdapter::OnAlias(const Mark& mark, anchor_t anchor)
|
||||
{
|
||||
void *pReffedNode = m_anchors[anchor];
|
||||
DispositionNode(m_builder.AnchorReference(mark, pReffedNode));
|
||||
}
|
||||
|
||||
void GraphBuilderAdapter::OnScalar(const Mark& mark, const std::string& tag, anchor_t anchor, const std::string& value)
|
||||
{
|
||||
void *pParent = GetCurrentParent();
|
||||
void *pNode = m_builder.NewScalar(mark, tag, pParent, value);
|
||||
RegisterAnchor(anchor, pNode);
|
||||
|
||||
DispositionNode(pNode);
|
||||
}
|
||||
|
||||
void GraphBuilderAdapter::OnSequenceStart(const Mark& mark, const std::string& tag, anchor_t anchor)
|
||||
{
|
||||
void *pNode = m_builder.NewSequence(mark, tag, GetCurrentParent());
|
||||
m_containers.push(ContainerFrame(pNode));
|
||||
RegisterAnchor(anchor, pNode);
|
||||
}
|
||||
|
||||
void GraphBuilderAdapter::OnSequenceEnd()
|
||||
{
|
||||
void *pSequence = m_containers.top().pContainer;
|
||||
m_containers.pop();
|
||||
|
||||
DispositionNode(pSequence);
|
||||
}
|
||||
|
||||
void GraphBuilderAdapter::OnMapStart(const Mark& mark, const std::string& tag, anchor_t anchor)
|
||||
{
|
||||
void *pNode = m_builder.NewMap(mark, tag, GetCurrentParent());
|
||||
m_containers.push(ContainerFrame(pNode, m_pKeyNode));
|
||||
m_pKeyNode = NULL;
|
||||
RegisterAnchor(anchor, pNode);
|
||||
}
|
||||
|
||||
void GraphBuilderAdapter::OnMapEnd()
|
||||
{
|
||||
void *pMap = m_containers.top().pContainer;
|
||||
m_pKeyNode = m_containers.top().pPrevKeyNode;
|
||||
m_containers.pop();
|
||||
DispositionNode(pMap);
|
||||
}
|
||||
|
||||
void *GraphBuilderAdapter::GetCurrentParent() const
|
||||
{
|
||||
if (m_containers.empty()) {
|
||||
return NULL;
|
||||
}
|
||||
return m_containers.top().pContainer;
|
||||
}
|
||||
|
||||
void GraphBuilderAdapter::RegisterAnchor(anchor_t anchor, void *pNode)
|
||||
{
|
||||
if (anchor) {
|
||||
m_anchors[anchor] = pNode;
|
||||
}
|
||||
}
|
||||
|
||||
void GraphBuilderAdapter::DispositionNode(void *pNode)
|
||||
{
|
||||
if (m_containers.empty()) {
|
||||
m_pRootNode = pNode;
|
||||
return;
|
||||
}
|
||||
|
||||
void *pContainer = m_containers.top().pContainer;
|
||||
if (m_containers.top().isMap()) {
|
||||
if (m_pKeyNode) {
|
||||
m_builder.AssignInMap(pContainer, m_pKeyNode, pNode);
|
||||
m_pKeyNode = NULL;
|
||||
} else {
|
||||
m_pKeyNode = pNode;
|
||||
}
|
||||
} else {
|
||||
m_builder.AppendToSequence(pContainer, pNode);
|
||||
}
|
||||
}
|
||||
}
|
67
src/graphbuilderadapter.h
Normal file
67
src/graphbuilderadapter.h
Normal file
@@ -0,0 +1,67 @@
|
||||
#ifndef GRAPHBUILDERADAPTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define GRAPHBUILDERADAPTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
#include <map>
|
||||
#include <stack>
|
||||
#include "eventhandler.h"
|
||||
#include "graphbuilder.h"
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
class GraphBuilderAdapter : public EventHandler
|
||||
{
|
||||
public:
|
||||
GraphBuilderAdapter(GraphBuilderInterface& builder)
|
||||
: m_builder(builder), m_pRootNode(NULL), m_pKeyNode(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void OnDocumentStart(const Mark& mark) {(void)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();
|
||||
|
||||
void *RootNode() const {return m_pRootNode;}
|
||||
|
||||
private:
|
||||
struct ContainerFrame
|
||||
{
|
||||
ContainerFrame(void *pSequence)
|
||||
: pContainer(pSequence), pPrevKeyNode(&sequenceMarker)
|
||||
{}
|
||||
ContainerFrame(void *pMap, void* pPrevKeyNode)
|
||||
: pContainer(pMap), pPrevKeyNode(pPrevKeyNode)
|
||||
{}
|
||||
|
||||
void *pContainer;
|
||||
void *pPrevKeyNode;
|
||||
|
||||
bool isMap() const {return pPrevKeyNode != &sequenceMarker;}
|
||||
|
||||
private:
|
||||
static int sequenceMarker;
|
||||
};
|
||||
typedef std::stack<ContainerFrame> ContainerStack;
|
||||
typedef std::map<anchor_t, void*> AnchorMap;
|
||||
|
||||
GraphBuilderInterface& m_builder;
|
||||
ContainerStack m_containers;
|
||||
AnchorMap m_anchors;
|
||||
void *m_pRootNode;
|
||||
void *m_pKeyNode;
|
||||
|
||||
void *GetCurrentParent() const;
|
||||
void RegisterAnchor(anchor_t anchor, void *pNode);
|
||||
void DispositionNode(void *pNode);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // GRAPHBUILDERADAPTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
165
src/map.cpp
165
src/map.cpp
@@ -1,24 +1,13 @@
|
||||
#include "map.h"
|
||||
#include "node.h"
|
||||
#include "scanner.h"
|
||||
#include "token.h"
|
||||
#include "eventhandler.h"
|
||||
#include "exceptions.h"
|
||||
#include "emitter.h"
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
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()
|
||||
{
|
||||
@@ -34,11 +23,6 @@ namespace YAML
|
||||
m_data.clear();
|
||||
}
|
||||
|
||||
Content *Map::Clone() const
|
||||
{
|
||||
return new Map(m_data);
|
||||
}
|
||||
|
||||
bool Map::GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const
|
||||
{
|
||||
it = m_data.begin();
|
||||
@@ -56,140 +40,7 @@ namespace YAML
|
||||
return m_data.size();
|
||||
}
|
||||
|
||||
void Map::Parse(Scanner *pScanner, ParserState& state)
|
||||
{
|
||||
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)
|
||||
void Map::Insert(std::auto_ptr<Node> pKey, std::auto_ptr<Node> pValue)
|
||||
{
|
||||
node_map::const_iterator it = m_data.find(pKey.get());
|
||||
if(it != m_data.end())
|
||||
@@ -198,12 +49,14 @@ namespace YAML
|
||||
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;
|
||||
for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it)
|
||||
out << Key << *it->first << Value << *it->second;
|
||||
out << EndMap;
|
||||
eventHandler.OnMapStart(mark, tag, anchor);
|
||||
for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) {
|
||||
it->first->EmitEvents(am, eventHandler);
|
||||
it->second->EmitEvents(am, eventHandler);
|
||||
}
|
||||
eventHandler.OnMapEnd();
|
||||
}
|
||||
|
||||
int Map::Compare(Content *pContent)
|
||||
|
15
src/map.h
15
src/map.h
@@ -19,17 +19,16 @@ namespace YAML
|
||||
|
||||
public:
|
||||
Map();
|
||||
Map(const node_map& data);
|
||||
virtual ~Map();
|
||||
|
||||
void Clear();
|
||||
virtual Content *Clone() 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 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; }
|
||||
|
||||
@@ -39,14 +38,6 @@ namespace YAML
|
||||
virtual int Compare(Sequence *) { return 1; }
|
||||
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:
|
||||
node_map m_data;
|
||||
};
|
||||
|
222
src/node.cpp
222
src/node.cpp
@@ -1,15 +1,20 @@
|
||||
#include "node.h"
|
||||
#include "token.h"
|
||||
#include "scanner.h"
|
||||
#include "content.h"
|
||||
#include "parser.h"
|
||||
#include "scalar.h"
|
||||
#include "sequence.h"
|
||||
#include "map.h"
|
||||
#include "aliascontent.h"
|
||||
#include "iterpriv.h"
|
||||
#include "aliasmanager.h"
|
||||
#include "content.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 "scanner.h"
|
||||
#include "sequence.h"
|
||||
#include "tag.h"
|
||||
#include "token.h"
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace YAML
|
||||
@@ -20,17 +25,10 @@ namespace YAML
|
||||
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()
|
||||
{
|
||||
Clear();
|
||||
@@ -42,138 +40,105 @@ namespace YAML
|
||||
m_pContent = 0;
|
||||
m_alias = false;
|
||||
m_referenced = false;
|
||||
m_anchor.clear();
|
||||
m_tag.clear();
|
||||
}
|
||||
|
||||
std::auto_ptr<Node> Node::Clone() const
|
||||
{
|
||||
if(m_alias)
|
||||
throw std::runtime_error("yaml-cpp: Can't clone alias"); // TODO: what to do about aliases?
|
||||
|
||||
return std::auto_ptr<Node> (new Node(m_mark, m_anchor, m_tag, m_pContent));
|
||||
std::auto_ptr<Node> pNode(new Node);
|
||||
NodeBuilder nodeBuilder(*pNode);
|
||||
EmitEvents(nodeBuilder);
|
||||
return pNode;
|
||||
}
|
||||
|
||||
void Node::Parse(Scanner *pScanner, ParserState& state)
|
||||
void Node::EmitEvents(EventHandler& eventHandler) const
|
||||
{
|
||||
eventHandler.OnDocumentStart(m_mark);
|
||||
AliasManager am;
|
||||
EmitEvents(am, eventHandler);
|
||||
eventHandler.OnDocumentEnd();
|
||||
}
|
||||
|
||||
void Node::EmitEvents(AliasManager& am, EventHandler& eventHandler) const
|
||||
{
|
||||
anchor_t anchor = NullAnchor;
|
||||
if(m_referenced || m_alias) {
|
||||
if(const Node *pOther = am.LookupReference(*this)) {
|
||||
eventHandler.OnAlias(m_mark, am.LookupAnchor(*pOther));
|
||||
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);
|
||||
}
|
||||
|
||||
void Node::Init(CONTENT_TYPE type, const Mark& mark, const std::string& tag)
|
||||
{
|
||||
Clear();
|
||||
m_mark = mark;
|
||||
m_tag = tag;
|
||||
m_alias = false;
|
||||
m_pIdentity = this;
|
||||
m_referenced = false;
|
||||
|
||||
// an empty node *is* a possibility
|
||||
if(pScanner->empty())
|
||||
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
|
||||
// being deleted twice
|
||||
Content *pAliasedContent = pReferencedNode->m_pContent;
|
||||
if(pAliasedContent)
|
||||
m_pContent = new AliasContent(pAliasedContent);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// now split based on what kind of node we should be
|
||||
switch(pScanner->peek().type) {
|
||||
case Token::SCALAR:
|
||||
switch(type) {
|
||||
case CT_SCALAR:
|
||||
m_pContent = new Scalar;
|
||||
break;
|
||||
case Token::FLOW_SEQ_START:
|
||||
case Token::BLOCK_SEQ_START:
|
||||
case CT_SEQUENCE:
|
||||
m_pContent = new Sequence;
|
||||
break;
|
||||
case Token::FLOW_MAP_START:
|
||||
case Token::BLOCK_MAP_START:
|
||||
case CT_MAP:
|
||||
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;
|
||||
break;
|
||||
default:
|
||||
m_pContent = 0;
|
||||
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
|
||||
// . Grabs any tag, alias, or anchor tokens and deals with them.
|
||||
void Node::ParseHeader(Scanner *pScanner, ParserState& state)
|
||||
void Node::InitNull(const std::string& tag)
|
||||
{
|
||||
while(1) {
|
||||
if(pScanner->empty())
|
||||
return;
|
||||
|
||||
switch(pScanner->peek().type) {
|
||||
case Token::TAG: ParseTag(pScanner, state); break;
|
||||
case Token::ANCHOR: ParseAnchor(pScanner, state); break;
|
||||
case Token::ALIAS: ParseAlias(pScanner, state); break;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
Clear();
|
||||
m_tag = tag;
|
||||
m_alias = false;
|
||||
m_pIdentity = this;
|
||||
m_referenced = false;
|
||||
}
|
||||
|
||||
void Node::ParseTag(Scanner *pScanner, ParserState& state)
|
||||
void Node::InitAlias(const Mark& mark, const Node& identity)
|
||||
{
|
||||
Token& token = pScanner->peek();
|
||||
if(m_tag != "")
|
||||
throw ParserException(token.mark, ErrorMsg::MULTIPLE_TAGS);
|
||||
Clear();
|
||||
m_mark = mark;
|
||||
m_alias = true;
|
||||
m_pIdentity = &identity;
|
||||
if(identity.m_pContent)
|
||||
m_pContent = new AliasContent(identity.m_pContent);
|
||||
identity.m_referenced = true;
|
||||
}
|
||||
|
||||
Tag tag(token);
|
||||
m_tag = tag.Translate(state);
|
||||
pScanner->pop();
|
||||
void Node::SetData(const std::string& data)
|
||||
{
|
||||
assert(m_pContent); // TODO: throw
|
||||
m_pContent->SetData(data);
|
||||
}
|
||||
|
||||
void Node::Append(std::auto_ptr<Node> pNode)
|
||||
{
|
||||
assert(m_pContent); // TODO: throw
|
||||
m_pContent->Append(pNode);
|
||||
}
|
||||
|
||||
void Node::ParseAnchor(Scanner *pScanner, ParserState& /*state*/)
|
||||
void Node::Insert(std::auto_ptr<Node> pKey, std::auto_ptr<Node> pValue)
|
||||
{
|
||||
Token& token = pScanner->peek();
|
||||
if(m_anchor != "")
|
||||
throw ParserException(token.mark, ErrorMsg::MULTIPLE_ANCHORS);
|
||||
|
||||
m_anchor = token.value;
|
||||
m_alias = false;
|
||||
pScanner->pop();
|
||||
}
|
||||
|
||||
void Node::ParseAlias(Scanner *pScanner, ParserState& /*state*/)
|
||||
{
|
||||
Token& token = pScanner->peek();
|
||||
if(m_anchor != "")
|
||||
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();
|
||||
assert(m_pContent); // TODO: throw
|
||||
m_pContent->Insert(pKey, pValue);
|
||||
}
|
||||
|
||||
CONTENT_TYPE Node::GetType() const
|
||||
@@ -261,23 +226,8 @@ namespace YAML
|
||||
|
||||
Emitter& operator << (Emitter& out, const Node& node)
|
||||
{
|
||||
// write anchor/alias
|
||||
if(node.m_anchor != "") {
|
||||
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;
|
||||
|
||||
EmitFromEvents emitFromEvents(out);
|
||||
node.EmitEvents(emitFromEvents);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
142
src/nodebuilder.cpp
Normal file
142
src/nodebuilder.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
#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);
|
||||
}
|
||||
}
|
||||
}
|
59
src/nodebuilder.h
Normal file
59
src/nodebuilder.h
Normal file
@@ -0,0 +1,59 @@
|
||||
#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
|
||||
|
@@ -1,8 +1,14 @@
|
||||
#include "parser.h"
|
||||
#include "scanner.h"
|
||||
#include "token.h"
|
||||
#include "directives.h"
|
||||
#include "eventhandler.h"
|
||||
#include "exceptions.h"
|
||||
#include "parserstate.h"
|
||||
#include "graphbuilderadapter.h"
|
||||
#include "node.h"
|
||||
#include "nodebuilder.h"
|
||||
#include "scanner.h"
|
||||
#include "singledocparser.h"
|
||||
#include "tag.h"
|
||||
#include "token.h"
|
||||
#include <sstream>
|
||||
#include <cstdio>
|
||||
|
||||
@@ -29,7 +35,38 @@ namespace YAML
|
||||
void Parser::Load(std::istream& in)
|
||||
{
|
||||
m_pScanner.reset(new Scanner(in));
|
||||
m_pState.reset(new ParserState);
|
||||
m_pDirectives.reset(new Directives);
|
||||
}
|
||||
|
||||
// HandleNextDocument
|
||||
// . Handles the next document
|
||||
// . Throws a ParserException on error.
|
||||
// . Returns false if there are no more documents
|
||||
bool Parser::HandleNextDocument(EventHandler& eventHandler)
|
||||
{
|
||||
if(!m_pScanner.get())
|
||||
return false;
|
||||
|
||||
ParseDirectives();
|
||||
if(m_pScanner->empty())
|
||||
return false;
|
||||
|
||||
SingleDocParser sdp(*m_pScanner, *m_pDirectives);
|
||||
sdp.HandleDocument(eventHandler);
|
||||
return true;
|
||||
}
|
||||
|
||||
// BuildNextDocumentGraph
|
||||
// . 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;
|
||||
}
|
||||
}
|
||||
|
||||
// GetNextDocument
|
||||
@@ -37,34 +74,8 @@ namespace YAML
|
||||
// . Throws a ParserException on error.
|
||||
bool Parser::GetNextDocument(Node& document)
|
||||
{
|
||||
if(!m_pScanner.get())
|
||||
return false;
|
||||
|
||||
// clear node
|
||||
document.Clear();
|
||||
|
||||
// first read directives
|
||||
ParseDirectives();
|
||||
|
||||
// we better have some tokens in the queue
|
||||
if(m_pScanner->empty())
|
||||
return false;
|
||||
|
||||
// first eat doc start (optional)
|
||||
if(m_pScanner->peek().type == Token::DOC_START)
|
||||
m_pScanner->pop();
|
||||
|
||||
// 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
|
||||
m_pScanner->ClearAnchors();
|
||||
|
||||
return true;
|
||||
NodeBuilder builder(document);
|
||||
return HandleNextDocument(builder);
|
||||
}
|
||||
|
||||
// ParseDirectives
|
||||
@@ -84,7 +95,7 @@ namespace YAML
|
||||
// we keep the directives from the last document if none are specified;
|
||||
// but if any directives are specific, then we reset them
|
||||
if(!readDirective)
|
||||
m_pState.reset(new ParserState);
|
||||
m_pDirectives.reset(new Directives);
|
||||
|
||||
readDirective = true;
|
||||
HandleDirective(token);
|
||||
@@ -107,20 +118,20 @@ namespace YAML
|
||||
if(token.params.size() != 1)
|
||||
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);
|
||||
|
||||
std::stringstream str(token.params[0]);
|
||||
str >> m_pState->version.major;
|
||||
str >> m_pDirectives->version.major;
|
||||
str.get();
|
||||
str >> m_pState->version.minor;
|
||||
str >> m_pDirectives->version.minor;
|
||||
if(!str || str.peek() != EOF)
|
||||
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);
|
||||
|
||||
m_pState->version.isDefault = false;
|
||||
m_pDirectives->version.isDefault = false;
|
||||
// TODO: warning on major == 1, minor > 2?
|
||||
}
|
||||
|
||||
@@ -133,10 +144,10 @@ namespace YAML
|
||||
|
||||
const std::string& handle = token.params[0];
|
||||
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);
|
||||
|
||||
m_pState->tags[handle] = prefix;
|
||||
m_pDirectives->tags[handle] = prefix;
|
||||
}
|
||||
|
||||
void Parser::PrintTokens(std::ostream& out)
|
||||
|
@@ -1,37 +0,0 @@
|
||||
#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
|
37
src/ptr_stack.h
Normal file
37
src/ptr_stack.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#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
|
@@ -1,9 +1,5 @@
|
||||
#include "scalar.h"
|
||||
#include "scanner.h"
|
||||
#include "token.h"
|
||||
#include "exceptions.h"
|
||||
#include "node.h"
|
||||
#include "emitter.h"
|
||||
#include "eventhandler.h"
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
@@ -11,29 +7,13 @@ namespace YAML
|
||||
{
|
||||
}
|
||||
|
||||
Scalar::Scalar(const std::string& data): m_data(data)
|
||||
{
|
||||
}
|
||||
|
||||
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)
|
||||
|
@@ -13,15 +13,12 @@ namespace YAML
|
||||
{
|
||||
public:
|
||||
Scalar();
|
||||
Scalar(const std::string& data);
|
||||
virtual ~Scalar();
|
||||
|
||||
virtual Content *Clone() const;
|
||||
|
||||
virtual void Parse(Scanner *pScanner, ParserState& state);
|
||||
virtual void Write(Emitter& out) const;
|
||||
virtual void SetData(const std::string& data) { m_data = data; }
|
||||
|
||||
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
|
||||
virtual bool GetScalar(std::string& scalar) const {
|
||||
|
@@ -32,13 +32,8 @@ namespace YAML
|
||||
void Scanner::pop()
|
||||
{
|
||||
EnsureTokensInQueue();
|
||||
if(!m_tokens.empty()) {
|
||||
// Saved anchors shouldn't survive popping the document end marker
|
||||
if (m_tokens.front().type == Token::DOC_END) {
|
||||
ClearAnchors();
|
||||
}
|
||||
if(!m_tokens.empty())
|
||||
m_tokens.pop();
|
||||
}
|
||||
}
|
||||
|
||||
// peek
|
||||
@@ -245,7 +240,6 @@ namespace YAML
|
||||
IndentMarker *pIndent = new IndentMarker(-1, IndentMarker::NONE);
|
||||
m_indentRefs.push_back(pIndent);
|
||||
m_indents.push(pIndent);
|
||||
m_anchors.clear();
|
||||
}
|
||||
|
||||
// EndStream
|
||||
@@ -378,29 +372,6 @@ namespace YAML
|
||||
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
|
||||
// . Throws a ParserException with the current token location
|
||||
// (if available).
|
||||
@@ -414,10 +385,5 @@ namespace YAML
|
||||
}
|
||||
throw ParserException(mark, msg);
|
||||
}
|
||||
|
||||
void Scanner::ClearAnchors()
|
||||
{
|
||||
m_anchors.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -29,11 +29,6 @@ namespace YAML
|
||||
void pop();
|
||||
Token& peek();
|
||||
|
||||
// anchor management
|
||||
void Save(const std::string& anchor, Node* value);
|
||||
const Node *Retrieve(const std::string& anchor) const;
|
||||
void ClearAnchors();
|
||||
|
||||
private:
|
||||
struct IndentMarker {
|
||||
enum INDENT_TYPE { MAP, SEQ, NONE };
|
||||
@@ -127,7 +122,6 @@ namespace YAML
|
||||
std::stack <IndentMarker *> m_indents;
|
||||
std::vector <IndentMarker *> m_indentRefs; // for "garbage collection"
|
||||
std::stack <FLOW_MARKER> m_flows;
|
||||
std::map <std::string, const Node *> m_anchors;
|
||||
};
|
||||
}
|
||||
|
||||
|
102
src/sequence.cpp
102
src/sequence.cpp
@@ -1,8 +1,6 @@
|
||||
#include "sequence.h"
|
||||
#include "eventhandler.h"
|
||||
#include "node.h"
|
||||
#include "scanner.h"
|
||||
#include "token.h"
|
||||
#include "emitter.h"
|
||||
#include <stdexcept>
|
||||
|
||||
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()
|
||||
{
|
||||
Clear();
|
||||
@@ -30,11 +22,6 @@ namespace YAML
|
||||
m_data.clear();
|
||||
}
|
||||
|
||||
Content *Sequence::Clone() const
|
||||
{
|
||||
return new Sequence(m_data);
|
||||
}
|
||||
|
||||
bool Sequence::GetBegin(std::vector <Node *>::const_iterator& it) const
|
||||
{
|
||||
it = m_data.begin();
|
||||
@@ -59,90 +46,17 @@ namespace YAML
|
||||
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;
|
||||
}
|
||||
m_data.push_back(pNode.release());
|
||||
}
|
||||
|
||||
void Sequence::ParseBlock(Scanner *pScanner, ParserState& state)
|
||||
|
||||
void Sequence::EmitEvents(AliasManager& am, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const
|
||||
{
|
||||
// eat start token
|
||||
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
|
||||
{
|
||||
out << BeginSeq;
|
||||
eventHandler.OnSequenceStart(mark, tag, anchor);
|
||||
for(std::size_t i=0;i<m_data.size();i++)
|
||||
out << *m_data[i];
|
||||
out << EndSeq;
|
||||
m_data[i]->EmitEvents(am, eventHandler);
|
||||
eventHandler.OnSequenceEnd();
|
||||
}
|
||||
|
||||
int Sequence::Compare(Content *pContent)
|
||||
|
@@ -15,19 +15,17 @@ namespace YAML
|
||||
{
|
||||
public:
|
||||
Sequence();
|
||||
Sequence(const std::vector<Node *>& data);
|
||||
virtual ~Sequence();
|
||||
|
||||
void Clear();
|
||||
virtual Content *Clone() const;
|
||||
|
||||
virtual bool GetBegin(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 std::size_t GetSize() const;
|
||||
|
||||
virtual void Parse(Scanner *pScanner, ParserState& state);
|
||||
virtual void Write(Emitter& out) const;
|
||||
virtual void Append(std::auto_ptr<Node> pNode);
|
||||
virtual void EmitEvents(AliasManager& am, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const;
|
||||
|
||||
virtual bool IsSequence() const { return true; }
|
||||
|
||||
@@ -37,10 +35,6 @@ namespace YAML
|
||||
virtual int Compare(Sequence *pSeq);
|
||||
virtual int Compare(Map *) { return -1; }
|
||||
|
||||
private:
|
||||
void ParseBlock(Scanner *pScanner, ParserState& state);
|
||||
void ParseFlow(Scanner *pScanner, ParserState& state);
|
||||
|
||||
protected:
|
||||
std::vector <Node *> m_data;
|
||||
};
|
||||
|
369
src/singledocparser.cpp
Normal file
369
src/singledocparser.cpp
Normal file
@@ -0,0 +1,369 @@
|
||||
#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;
|
||||
}
|
||||
}
|
63
src/singledocparser.h
Normal file
63
src/singledocparser.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#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
|
10
src/tag.cpp
10
src/tag.cpp
@@ -1,6 +1,6 @@
|
||||
#include "tag.h"
|
||||
#include "directives.h"
|
||||
#include "token.h"
|
||||
#include "parserstate.h"
|
||||
#include <cassert>
|
||||
|
||||
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) {
|
||||
case VERBATIM:
|
||||
return value;
|
||||
case PRIMARY_HANDLE:
|
||||
return state.TranslateTagHandle("!") + value;
|
||||
return directives.TranslateTagHandle("!") + value;
|
||||
case SECONDARY_HANDLE:
|
||||
return state.TranslateTagHandle("!!") + value;
|
||||
return directives.TranslateTagHandle("!!") + value;
|
||||
case NAMED_HANDLE:
|
||||
return state.TranslateTagHandle("!" + handle + "!") + value;
|
||||
return directives.TranslateTagHandle("!" + handle + "!") + value;
|
||||
case NON_SPECIFIC:
|
||||
// TODO:
|
||||
return "!";
|
||||
|
@@ -8,7 +8,7 @@
|
||||
namespace YAML
|
||||
{
|
||||
struct Token;
|
||||
struct ParserState;
|
||||
struct Directives;
|
||||
|
||||
struct Tag {
|
||||
enum TYPE {
|
||||
@@ -16,7 +16,7 @@ namespace YAML
|
||||
};
|
||||
|
||||
Tag(const Token& token);
|
||||
const std::string Translate(const ParserState& state);
|
||||
const std::string Translate(const Directives& directives);
|
||||
|
||||
TYPE type;
|
||||
std::string handle, value;
|
||||
|
@@ -1,9 +1,25 @@
|
||||
#include "yaml.h"
|
||||
#include <fstream>
|
||||
#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)
|
||||
{
|
||||
Params p = ParseArgs(argc, argv);
|
||||
|
||||
std::ifstream fin;
|
||||
if(argc > 1)
|
||||
fin.open(argv[1]);
|
||||
|
Reference in New Issue
Block a user