From 0134c553a50dc9fef785a2ecefa2d3e8cec9715e Mon Sep 17 00:00:00 2001 From: beder Date: Wed, 25 Jun 2008 22:45:08 +0000 Subject: [PATCH 002/295] --- document.cpp | 29 +++++++++++++++++++++++++++++ document.h | 22 ++++++++++++++++++++++ main.cpp | 8 ++++++++ node.cpp | 12 ++++++++++++ node.h | 20 ++++++++++++++++++++ test.yaml | 2 ++ 6 files changed, 93 insertions(+) create mode 100644 document.cpp create mode 100644 document.h create mode 100644 main.cpp create mode 100644 node.cpp create mode 100644 node.h create mode 100644 test.yaml diff --git a/document.cpp b/document.cpp new file mode 100644 index 0000000..a9ff19a --- /dev/null +++ b/document.cpp @@ -0,0 +1,29 @@ +#include "document.h" +#include "node.h" + +namespace YAML +{ + Document::Document(): m_pRoot(0) + { + } + + Document::Document(const std::string& fileName): m_pRoot(0) + { + Load(fileName); + } + + Document::~Document() + { + Clear(); + } + + void Document::Clear() + { + delete m_pRoot; + m_pRoot = 0; + } + + void Document::Load(const std::string& fileName) + { + } +} diff --git a/document.h b/document.h new file mode 100644 index 0000000..285bf94 --- /dev/null +++ b/document.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +namespace YAML +{ + class Node; + + class Document + { + public: + Document(); + Document(const std::string& fileName); + ~Document(); + + void Clear(); + void Load(const std::string& fileName); + + private: + Node *m_pRoot; + }; +} diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..f5f3fa8 --- /dev/null +++ b/main.cpp @@ -0,0 +1,8 @@ +#include "document.h" + +int main() +{ + YAML::Document doc("test.yaml"); + + return 0; +} \ No newline at end of file diff --git a/node.cpp b/node.cpp new file mode 100644 index 0000000..22c1beb --- /dev/null +++ b/node.cpp @@ -0,0 +1,12 @@ +#include "node.h" + +namespace YAML +{ + Node::Node() + { + } + + Node::~Node() + { + } +} diff --git a/node.h b/node.h new file mode 100644 index 0000000..dd4d362 --- /dev/null +++ b/node.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace YAML +{ + const std::string Str = "!!str"; + const std::string Seq = "!!seq"; + const std::string Map = "!!map"; + + class Node + { + public: + Node(); + ~Node(); + + private: + std::string m_tag; + }; +} diff --git a/test.yaml b/test.yaml new file mode 100644 index 0000000..dfd38a0 --- /dev/null +++ b/test.yaml @@ -0,0 +1,2 @@ +--- +test \ No newline at end of file From ffaf6a19caf7713eae96b69d138474e1ed46f0da Mon Sep 17 00:00:00 2001 From: beder Date: Wed, 25 Jun 2008 22:46:18 +0000 Subject: [PATCH 003/295] --- yaml-reader.sln | 20 +++++ yaml-reader.vcproj | 200 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 220 insertions(+) create mode 100644 yaml-reader.sln create mode 100644 yaml-reader.vcproj diff --git a/yaml-reader.sln b/yaml-reader.sln new file mode 100644 index 0000000..1fe1807 --- /dev/null +++ b/yaml-reader.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml-reader", "yaml-reader.vcproj", "{E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}.Debug|Win32.ActiveCfg = Debug|Win32 + {E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}.Debug|Win32.Build.0 = Debug|Win32 + {E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}.Release|Win32.ActiveCfg = Release|Win32 + {E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj new file mode 100644 index 0000000..def7c75 --- /dev/null +++ b/yaml-reader.vcproj @@ -0,0 +1,200 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 2d0f324529f3f7d4ed2b6d1e4a94a2ab16468eaf Mon Sep 17 00:00:00 2001 From: beder Date: Wed, 25 Jun 2008 23:00:18 +0000 Subject: [PATCH 004/295] Preliminary setup - basic data structures are there. --- content.cpp | 12 ++++++++++++ content.h | 13 +++++++++++++ document.cpp | 6 ++++++ map.cpp | 17 +++++++++++++++++ map.h | 20 ++++++++++++++++++++ node.cpp | 14 +++++++++++++- node.h | 13 ++++++++++--- scalar.cpp | 12 ++++++++++++ scalar.h | 17 +++++++++++++++++ sequence.cpp | 15 +++++++++++++++ sequence.h | 19 +++++++++++++++++++ yaml-reader.vcproj | 32 ++++++++++++++++++++++++++++++++ 12 files changed, 186 insertions(+), 4 deletions(-) create mode 100644 content.cpp create mode 100644 content.h create mode 100644 map.cpp create mode 100644 map.h create mode 100644 scalar.cpp create mode 100644 scalar.h create mode 100644 sequence.cpp create mode 100644 sequence.h diff --git a/content.cpp b/content.cpp new file mode 100644 index 0000000..b68bb25 --- /dev/null +++ b/content.cpp @@ -0,0 +1,12 @@ +#include "content.h" + +namespace YAML +{ + Content::Content() + { + } + + Content::~Content() + { + } +} diff --git a/content.h b/content.h new file mode 100644 index 0000000..d251bb1 --- /dev/null +++ b/content.h @@ -0,0 +1,13 @@ +#pragma once + +namespace YAML +{ + class Content + { + public: + Content(); + virtual ~Content(); + + protected: + }; +} diff --git a/document.cpp b/document.cpp index a9ff19a..750ef65 100644 --- a/document.cpp +++ b/document.cpp @@ -1,5 +1,6 @@ #include "document.h" #include "node.h" +#include namespace YAML { @@ -25,5 +26,10 @@ namespace YAML void Document::Load(const std::string& fileName) { + Clear(); + + std::ifstream fin(fileName.c_str()); + m_pRoot = new Node; + m_pRoot->Read(fin); } } diff --git a/map.cpp b/map.cpp new file mode 100644 index 0000000..882ad15 --- /dev/null +++ b/map.cpp @@ -0,0 +1,17 @@ +#include "map.h" +#include "node.h" + +namespace YAML +{ + Map::Map() + { + } + + Map::~Map() + { + for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) { + delete it->first; + delete it->second; + } + } +} diff --git a/map.h b/map.h new file mode 100644 index 0000000..b165ac5 --- /dev/null +++ b/map.h @@ -0,0 +1,20 @@ +#pragma once + +#include "content.h" +#include + +namespace YAML +{ + class Node; + + class Map: public Content + { + public: + Map(); + virtual ~Map(); + + protected: + typedef std::map node_map; + node_map m_data; + }; +} diff --git a/node.cpp b/node.cpp index 22c1beb..0da7c2b 100644 --- a/node.cpp +++ b/node.cpp @@ -1,12 +1,24 @@ #include "node.h" +#include "content.h" namespace YAML { - Node::Node() + Node::Node(): m_pContent(0) { } Node::~Node() + { + Clear(); + } + + void Node::Clear() + { + delete m_pContent; + m_pContent = 0; + } + + void Node::Read(std::istream& in) { } } diff --git a/node.h b/node.h index dd4d362..e1e5d1d 100644 --- a/node.h +++ b/node.h @@ -1,12 +1,15 @@ #pragma once #include +#include namespace YAML { - const std::string Str = "!!str"; - const std::string Seq = "!!seq"; - const std::string Map = "!!map"; + const std::string StrTag = "!!str"; + const std::string SeqTag = "!!seq"; + const std::string MapTag = "!!map"; + + class Content; class Node { @@ -14,7 +17,11 @@ namespace YAML Node(); ~Node(); + void Clear(); + void Read(std::istream& in); + private: std::string m_tag; + Content *m_pContent; }; } diff --git a/scalar.cpp b/scalar.cpp new file mode 100644 index 0000000..787e096 --- /dev/null +++ b/scalar.cpp @@ -0,0 +1,12 @@ +#include "scalar.h" + +namespace YAML +{ + Scalar::Scalar() + { + } + + Scalar::~Scalar() + { + } +} diff --git a/scalar.h b/scalar.h new file mode 100644 index 0000000..5f3e068 --- /dev/null +++ b/scalar.h @@ -0,0 +1,17 @@ +#pragma once + +#include "content.h" +#include + +namespace YAML +{ + class Scalar: public Content + { + public: + Scalar(); + virtual ~Scalar(); + + protected: + std::string m_data; + }; +} diff --git a/sequence.cpp b/sequence.cpp new file mode 100644 index 0000000..ef1d336 --- /dev/null +++ b/sequence.cpp @@ -0,0 +1,15 @@ +#include "sequence.h" +#include "node.h" + +namespace YAML +{ + Sequence::Sequence() + { + } + + Sequence::~Sequence() + { + for(unsigned i=0;i + +namespace YAML +{ + class Node; + + class Sequence: public Content + { + public: + Sequence(); + virtual ~Sequence(); + + protected: + std::vector m_data; + }; +} diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index def7c75..d5ea568 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -161,6 +161,10 @@ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > + + @@ -169,24 +173,52 @@ RelativePath=".\main.cpp" > + + + + + + + + + + + + + + Date: Thu, 26 Jun 2008 06:49:50 +0000 Subject: [PATCH 005/295] Beginning of first attempt to parse. Will be completely wiped, I think, in favor of a Scanner (to tokens), then Parser mechanism. --- document.cpp | 8 ++- node.cpp | 12 +++- node.h | 3 +- parser.cpp | 141 +++++++++++++++++++++++++++++++++++++++++++++ parser.h | 55 ++++++++++++++++++ scalar.cpp | 2 +- scalar.h | 2 +- sequence.cpp | 12 +++- sequence.h | 5 +- test.yaml | 4 +- yaml-reader.vcproj | 12 ++++ 11 files changed, 247 insertions(+), 9 deletions(-) create mode 100644 parser.cpp create mode 100644 parser.h diff --git a/document.cpp b/document.cpp index 750ef65..953ac6d 100644 --- a/document.cpp +++ b/document.cpp @@ -1,5 +1,6 @@ #include "document.h" #include "node.h" +#include "parser.h" #include namespace YAML @@ -29,7 +30,10 @@ namespace YAML Clear(); std::ifstream fin(fileName.c_str()); - m_pRoot = new Node; - m_pRoot->Read(fin); + Parser parser(fin); + if(!parser) + return; + + m_pRoot = parser.ReadNextNode(); } } diff --git a/node.cpp b/node.cpp index 0da7c2b..33c688f 100644 --- a/node.cpp +++ b/node.cpp @@ -1,5 +1,8 @@ #include "node.h" #include "content.h" +#include "parser.h" +#include "scalar.h" +#include "sequence.h" namespace YAML { @@ -18,7 +21,14 @@ namespace YAML m_pContent = 0; } - void Node::Read(std::istream& in) + void Node::Read(Parser *pParser, const std::string& token) { + Clear(); + + if(token == std::string("") + SeqToken) { + m_pContent = new Sequence(pParser); + } else { + m_pContent = new Scalar(token); + } } } diff --git a/node.h b/node.h index e1e5d1d..c8bd7e5 100644 --- a/node.h +++ b/node.h @@ -10,6 +10,7 @@ namespace YAML const std::string MapTag = "!!map"; class Content; + class Parser; class Node { @@ -18,7 +19,7 @@ namespace YAML ~Node(); void Clear(); - void Read(std::istream& in); + void Read(Parser *pParser, const std::string& token); private: std::string m_tag; diff --git a/parser.cpp b/parser.cpp new file mode 100644 index 0000000..999fa90 --- /dev/null +++ b/parser.cpp @@ -0,0 +1,141 @@ +#include "parser.h" +#include "node.h" + +namespace YAML +{ + Parser::Parser(std::istream& in): INPUT(in), m_ok(true) + { + m_state.push(State(C_BLOCK, -1, true)); + + // read header + std::string token = ReadNextToken(); + if(token != DocStart) + m_ok = false; + } + + Parser::~Parser() + { + } + + Parser::operator bool() const + { + return m_ok; + } + + bool Parser::operator !() const + { + return !m_ok; + } + + bool Parser::IsWhitespace(char ch) + { + return (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'); + } + + void Parser::Putback(const std::string& str) + { + for(int i=str.size()-1;i>=0;i--) + INPUT.putback(str[i]); + } + + // StringWhitespace + // . Strips up to n whitespace characters (or as many + // as there are, if n is -1) + void Parser::StripWhitespace(int n) + { + while(--n >= 0 && IsWhitespace(INPUT.peek())) + INPUT.get(); + } + + int Parser::GetNumOfSpaces() + { + // get 'em out + int n = 0; + while(INPUT.peek() == ' ') { + INPUT.get(); + n++; + } + + // put 'em back + for(int i=0;iRead(this, token); + return pNode; + } + + // ReadNextToken + // . Reads: + // . If the first character is non-whitespace, non-special token, then until + // the end of this scalar. + std::string Parser::ReadNextToken() + { + const State& state = m_state.top(); + + if(state.startingNewLine) { + int n = GetNumOfSpaces(); + StripWhitespace(n); + if(n > state.indent) { + m_state.push(State(C_BLOCK, n, true)); + }; + + while(m_state.top().startingNewLine && n < m_state.top().indent) + m_state.pop(); + } + + char ch = INPUT.peek(); + if(IsWhitespace(ch)) + return ""; // TODO + + if(ch == SeqToken) { + // grab token + INPUT.get(); + + // is next token whitespace? + if(!IsWhitespace(INPUT.peek())) { + // read entire line + std::string line; + std::getline(INPUT, line); + return ch + line; + } + + // if so, strip whitespace and go + StripWhitespace(); + + return std::string("") + SeqToken; + } + + // read until end-of-line + std::string line; + std::getline(INPUT, line); + return line; + } +} diff --git a/parser.h b/parser.h new file mode 100644 index 0000000..fbbae0b --- /dev/null +++ b/parser.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include + +namespace YAML +{ + class Node; + + const std::string DocStart = "---"; + const std::string DocEnd = "..."; + + const char SeqToken = '-'; + + enum CONTEXT { C_BLOCK, C_FLOW }; + + class Parser + { + public: + struct State + { + State(CONTEXT context_, int indent_, bool startingNewLine_) + : context(context_), indent(indent_), startingNewLine(startingNewLine_) {} + + CONTEXT context; + int indent; + bool startingNewLine; + }; + + public: + Parser(std::istream& in); + ~Parser(); + + operator bool () const; + bool operator !() const; + + // parse helpers + static bool IsWhitespace(char ch); + void Putback(const std::string& str); + void StripWhitespace(int n = -1); + int GetNumOfSpaces(); + bool SeqContinues(); + + // readers + Node *ReadNextNode(); + std::string ReadNextToken(); + + private: + bool m_ok; + + std::istream& INPUT; + std::stack m_state; + }; +} diff --git a/scalar.cpp b/scalar.cpp index 787e096..4552194 100644 --- a/scalar.cpp +++ b/scalar.cpp @@ -2,7 +2,7 @@ namespace YAML { - Scalar::Scalar() + Scalar::Scalar(const std::string& data): m_data(data) { } diff --git a/scalar.h b/scalar.h index 5f3e068..79b69d6 100644 --- a/scalar.h +++ b/scalar.h @@ -8,7 +8,7 @@ namespace YAML class Scalar: public Content { public: - Scalar(); + Scalar(const std::string& data); virtual ~Scalar(); protected: diff --git a/sequence.cpp b/sequence.cpp index ef1d336..c9d3e4c 100644 --- a/sequence.cpp +++ b/sequence.cpp @@ -1,10 +1,12 @@ #include "sequence.h" #include "node.h" +#include "parser.h" namespace YAML { - Sequence::Sequence() + Sequence::Sequence(Parser *pParser) { + Read(pParser); } Sequence::~Sequence() @@ -12,4 +14,12 @@ namespace YAML for(unsigned i=0;iReadNextNode(); + m_data.push_back(pNode); + } while(pParser->SeqContinues()); + } } diff --git a/sequence.h b/sequence.h index cf7d1dd..f230505 100644 --- a/sequence.h +++ b/sequence.h @@ -6,13 +6,16 @@ namespace YAML { class Node; + class Parser; class Sequence: public Content { public: - Sequence(); + Sequence(Parser *pParser); virtual ~Sequence(); + void Read(Parser *pParser); + protected: std::vector m_data; }; diff --git a/test.yaml b/test.yaml index dfd38a0..7ac0238 100644 --- a/test.yaml +++ b/test.yaml @@ -1,2 +1,4 @@ --- -test \ No newline at end of file +- milk +- eggs +- cheese \ No newline at end of file diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index d5ea568..a235c5c 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -181,6 +181,10 @@ RelativePath=".\node.cpp" > + + @@ -211,6 +215,10 @@ RelativePath=".\node.h" > + + @@ -225,6 +233,10 @@ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > + + From 4b33531240c31a13910d9a0f136f4bcdd68f33f6 Mon Sep 17 00:00:00 2001 From: beder Date: Thu, 26 Jun 2008 09:05:28 +0000 Subject: [PATCH 006/295] Started the scanner. --- document.cpp | 10 +- scanner.cpp | 275 +++++++++++++++++++++++++++++++++++++++++++++ scanner.h | 55 +++++++++ token.h | 10 ++ yaml-reader.vcproj | 12 ++ 5 files changed, 358 insertions(+), 4 deletions(-) create mode 100644 scanner.cpp create mode 100644 scanner.h create mode 100644 token.h diff --git a/document.cpp b/document.cpp index 953ac6d..b55fb1e 100644 --- a/document.cpp +++ b/document.cpp @@ -1,6 +1,7 @@ #include "document.h" #include "node.h" #include "parser.h" +#include "scanner.h" #include namespace YAML @@ -30,10 +31,11 @@ namespace YAML Clear(); std::ifstream fin(fileName.c_str()); - Parser parser(fin); - if(!parser) - return; + Scanner scanner(fin); + scanner.Scan(); +// if(!scanner) +// return; - m_pRoot = parser.ReadNextNode(); +// m_pRoot = parser.ReadNextNode(); } } diff --git a/scanner.cpp b/scanner.cpp new file mode 100644 index 0000000..f28ba67 --- /dev/null +++ b/scanner.cpp @@ -0,0 +1,275 @@ +#include "scanner.h" +#include "token.h" + +namespace YAML +{ + Scanner::Scanner(std::istream& in) + : INPUT(in), m_startedStream(false), m_simpleKeyAllowed(false), m_flowLevel(0), m_column(0) + { + } + + Scanner::~Scanner() + { + } + + /////////////////////////////////////////////////////////////////////// + // Misc. helpers + + // GetChar + // . Extracts a character from the stream and updates our position + char Scanner::GetChar() + { + m_column++; + return INPUT.get(); + } + + // GetLineBreak + // . Eats with no checking + void Scanner::EatLineBreak() + { + m_column = 0; + INPUT.get(); + } + + // EatDocumentStart + // . Eats with no checking + void Scanner::EatDocumentStart() + { + INPUT.get(); + INPUT.get(); + INPUT.get(); + } + + // EatDocumentEnd + // . Eats with no checking + void Scanner::EatDocumentEnd() + { + INPUT.get(); + INPUT.get(); + INPUT.get(); + } + + // IsWhitespaceToBeEaten + // . We can eat whitespace if: + // 1. It's a space + // 2. It's a tab, and we're either: + // a. In the flow context + // b. In the block context but not where a simple key could be allowed + // (i.e., not at the beginning of a line, or following '-', '?', or ':') + bool Scanner::IsWhitespaceToBeEaten() + { + char ch = INPUT.peek(); + + if(ch == ' ') + return true; + + if(ch == '\t' && (m_flowLevel >= 0 || !m_simpleKeyAllowed)) + return true; + + return false; + } + + // IsLineBreak + bool Scanner::IsLineBreak() + { + char ch = INPUT.peek(); + return ch == '\n'; // TODO: More types of line breaks + } + + // IsBlank + bool Scanner::IsBlank() + { + char ch = INPUT.peek(); + return IsLineBreak() || ch == ' ' || ch == '\t' || ch == EOF; + } + + // IsDocumentStart + bool Scanner::IsDocumentStart() + { + // needs to be at the start of a new line + if(m_column != 0) + return false; + + // then needs '---' + for(int i=0;i<3;i++) { + if(INPUT.peek() != '-') { + // first put 'em back + for(int j=0;j StreamStartToken *Scanner::ScanToken(StreamStartToken *pToken) + { + m_startedStream = true; + m_simpleKeyAllowed = true; + m_indents.push(-1); + + return pToken; + } + + // StreamEndToken + template <> StreamEndToken *Scanner::ScanToken(StreamEndToken *pToken) + { + // force newline + if(m_column > 0) + m_column = 0; + + // TODO: unroll indentation + // TODO: "reset simple keys" + + m_simpleKeyAllowed = false; + + return pToken; + } + + // DocumentStartToken + template <> DocumentStartToken *Scanner::ScanToken(DocumentStartToken *pToken) + { + // TODO: unroll indentation + // TODO: reset simple keys + + m_simpleKeyAllowed = false; + + // eat it + EatDocumentStart(); + + return pToken; + } + + // DocumentEndToken + template <> DocumentEndToken *Scanner::ScanToken(DocumentEndToken *pToken) + { + // TODO: unroll indentation + // TODO: reset simple keys + + m_simpleKeyAllowed = false; + + // eat it + EatDocumentEnd(); + + return pToken; + } + + /////////////////////////////////////////////////////////////////////// + // The main scanning function + + Token *Scanner::ScanNextToken() + { + if(!m_startedStream) + return ScanToken(new StreamStartToken); + + ScanToNextToken(); + // TODO: remove "obsolete potential simple keys" + // TODO: unroll indent + + if(INPUT.peek() == EOF) + return ScanToken(new StreamEndToken); + + if(IsDocumentStart()) + return ScanToken(new DocumentStartToken); + + if(IsDocumentEnd()) + return ScanToken(new DocumentEndToken); + + return 0; + } + + // ScanToNextToken + // . Eats input until we reach the next token-like thing. + void Scanner::ScanToNextToken() + { + while(1) { + // first eat whitespace + while(IsWhitespaceToBeEaten()) + INPUT.get(); + + // then eat a comment + if(INPUT.peek() == Keys::Comment) { + // eat until line break + while(INPUT && !IsLineBreak()) + INPUT.get(); + } + + // if it's NOT a line break, then we're done! + if(!IsLineBreak()) + break; + + // otherwise, let's eat the line break and keep going + EatLineBreak(); + + // new line - we may be able to accept a simple key now + if(m_flowLevel == 0) + m_simpleKeyAllowed = true; + } + } + + // temporary function for testing + void Scanner::Scan() + { + while(Token *pToken = ScanNextToken()) + delete pToken; + } +} diff --git a/scanner.h b/scanner.h new file mode 100644 index 0000000..7fd8f5a --- /dev/null +++ b/scanner.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include +#include + +namespace YAML +{ + class Token; + + namespace Keys + { + const char Comment = '#'; + } + + class Scanner + { + public: + Scanner(std::istream& in); + ~Scanner(); + + Token *ScanNextToken(); + void ScanToNextToken(); + + void Scan(); + + private: + char GetChar(); + void EatLineBreak(); + void EatDocumentStart(); + void EatDocumentEnd(); + + bool IsWhitespaceToBeEaten(); + bool IsLineBreak(); + bool IsBlank(); + bool IsDocumentStart(); + bool IsDocumentEnd(); + template T *ScanToken(T *pToken); + + private: + // the stream + std::istream& INPUT; + int m_column; + + // the output (tokens) + std::queue m_tokens; + + // state info + bool m_startedStream; + bool m_simpleKeyAllowed; + int m_flowLevel; // number of unclosed '[' and '{' indicators + std::stack m_indents; + }; +} diff --git a/token.h b/token.h new file mode 100644 index 0000000..699b93b --- /dev/null +++ b/token.h @@ -0,0 +1,10 @@ +#pragma once + +namespace YAML +{ + class Token {}; + class StreamStartToken: public Token {}; + class StreamEndToken: public Token {}; + class DocumentStartToken: public Token {}; + class DocumentEndToken: public Token {}; +} diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index a235c5c..88eb74d 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -189,6 +189,10 @@ RelativePath=".\scalar.cpp" > + + @@ -223,10 +227,18 @@ RelativePath=".\scalar.h" > + + + + Date: Thu, 26 Jun 2008 19:30:11 +0000 Subject: [PATCH 007/295] Continued working on scanner. We're now using exceptions for errors, and scanning/pushing tokens is exception-safe (using a set of "limbo tokens"). --- document.cpp | 7 +- exceptions.h | 14 ++ scanner.cpp | 410 +++++++++++++++++++++++++++++++++++++++++++-- scanner.h | 25 ++- token.h | 17 ++ yaml-reader.vcproj | 4 + 6 files changed, 461 insertions(+), 16 deletions(-) create mode 100644 exceptions.h diff --git a/document.cpp b/document.cpp index b55fb1e..8ba707d 100644 --- a/document.cpp +++ b/document.cpp @@ -2,6 +2,7 @@ #include "node.h" #include "parser.h" #include "scanner.h" +#include "exceptions.h" #include namespace YAML @@ -32,7 +33,11 @@ namespace YAML std::ifstream fin(fileName.c_str()); Scanner scanner(fin); - scanner.Scan(); + + try { + scanner.Scan(); + } catch(const UnknownToken& e) { + } // if(!scanner) // return; diff --git a/exceptions.h b/exceptions.h new file mode 100644 index 0000000..947b924 --- /dev/null +++ b/exceptions.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +namespace YAML +{ + class Exception: public std::exception {}; + + class UnknownToken: public Exception {}; + class IllegalBlockEntry: public Exception {}; + class IllegalMapKey: public Exception {}; + class IllegalMapValue: public Exception {}; + class IllegalScalar: public Exception {}; +} diff --git a/scanner.cpp b/scanner.cpp index f28ba67..5320b29 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -1,5 +1,6 @@ #include "scanner.h" #include "token.h" +#include "exceptions.h" namespace YAML { @@ -10,6 +11,14 @@ namespace YAML Scanner::~Scanner() { + while(!m_tokens.empty()) { + delete m_tokens.front(); + m_tokens.pop(); + } + + // delete limbo tokens (they're here for RAII) + for(std::set ::const_iterator it=m_limboTokens.begin();it!=m_limboTokens.end();++it) + delete *it; } /////////////////////////////////////////////////////////////////////// @@ -157,9 +166,118 @@ namespace YAML return true; } + // IsBlockEntry + bool Scanner::IsBlockEntry() + { + if(INPUT.peek() != Keys::BlockEntry) + return false; + + INPUT.get(); + + // then needs a blank character (or eof) + if(!IsBlank()) { + INPUT.putback(Keys::BlockEntry); + return false; + } + + INPUT.putback(Keys::BlockEntry); + return true; + } + + // IsKey + bool Scanner::IsKey() + { + if(INPUT.peek() != Keys::Key) + return false; + + INPUT.get(); + + // then needs a blank character (or eof), if we're in block context + if(m_flowLevel == 0 && !IsBlank()) { + INPUT.putback(Keys::BlockEntry); + return false; + } + + INPUT.putback(Keys::BlockEntry); + return true; + } + + // IsValue + bool Scanner::IsValue() + { + if(INPUT.peek() != Keys::Value) + return false; + + INPUT.get(); + + // then needs a blank character (or eof), if we're in block context + if(m_flowLevel == 0 && !IsBlank()) { + INPUT.putback(Keys::BlockEntry); + return false; + } + + INPUT.putback(Keys::BlockEntry); + return true; + } + + // IsPlainScalar + // . Rules: + // . Cannot start with a blank. + // . Can never start with any of , [ ] { } # & * ! | > \' \" % @ ` + // . In the block context - ? : must be not be followed with a space. + // . In the flow context ? : are illegal and - must not be followed with a space. + bool Scanner::IsPlainScalar() + { + if(IsBlank()) + return false; + + // never characters + std::string never = ",[]{}#&*!|>\'\"%@`"; + for(unsigned i=0;i void Scanner::ScanAndEnqueue(T *pToken) + { + m_limboTokens.insert(pToken); + m_tokens.push(ScanToken(pToken)); + m_limboTokens.erase(pToken); + } + // StreamStartToken template <> StreamStartToken *Scanner::ScanToken(StreamStartToken *pToken) { @@ -177,7 +295,7 @@ namespace YAML if(m_column > 0) m_column = 0; - // TODO: unroll indentation + PopIndentTo(-1); // TODO: "reset simple keys" m_simpleKeyAllowed = false; @@ -188,8 +306,8 @@ namespace YAML // DocumentStartToken template <> DocumentStartToken *Scanner::ScanToken(DocumentStartToken *pToken) { - // TODO: unroll indentation - // TODO: reset simple keys + PopIndentTo(m_column); + // TODO: "reset simple keys" m_simpleKeyAllowed = false; @@ -202,8 +320,8 @@ namespace YAML // DocumentEndToken template <> DocumentEndToken *Scanner::ScanToken(DocumentEndToken *pToken) { - // TODO: unroll indentation - // TODO: reset simple keys + PopIndentTo(m_column); + // TODO: "reset simple keys" m_simpleKeyAllowed = false; @@ -213,28 +331,255 @@ namespace YAML return pToken; } + // FlowSeqStartToken + template <> FlowSeqStartToken *Scanner::ScanToken(FlowSeqStartToken *pToken) + { + // TODO: "save simple key" + // TODO: increase flow level + + m_simpleKeyAllowed = true; + + // eat it + INPUT.get(); + + return pToken; + } + + // FlowMapStartToken + template <> FlowMapStartToken *Scanner::ScanToken(FlowMapStartToken *pToken) + { + // TODO: "save simple key" + // TODO: increase flow level + + m_simpleKeyAllowed = true; + + // eat it + INPUT.get(); + + return pToken; + } + + // FlowSeqEndToken + template <> FlowSeqEndToken *Scanner::ScanToken(FlowSeqEndToken *pToken) + { + // TODO: "remove simple key" + // TODO: decrease flow level + + m_simpleKeyAllowed = false; + + // eat it + INPUT.get(); + + return pToken; + } + + // FlowMapEndToken + template <> FlowMapEndToken *Scanner::ScanToken(FlowMapEndToken *pToken) + { + // TODO: "remove simple key" + // TODO: decrease flow level + + m_simpleKeyAllowed = false; + + // eat it + INPUT.get(); + + return pToken; + } + + // FlowEntryToken + template <> FlowEntryToken *Scanner::ScanToken(FlowEntryToken *pToken) + { + // TODO: "remove simple key" + + m_simpleKeyAllowed = true; + + // eat it + INPUT.get(); + + return pToken; + } + + // BlockEntryToken + template <> BlockEntryToken *Scanner::ScanToken(BlockEntryToken *pToken) + { + // we better be in the block context! + if(m_flowLevel == 0) { + // can we put it here? + if(!m_simpleKeyAllowed) + throw IllegalBlockEntry(); + + PushIndentTo(m_column, true); // , -1 + } else { + // TODO: throw? + } + + // TODO: "remove simple key" + + m_simpleKeyAllowed = true; + + // eat + INPUT.get(); + return pToken; + } + + // KeyToken + template <> KeyToken *Scanner::ScanToken(KeyToken *pToken) + { + // are we in block context? + if(m_flowLevel == 0) { + if(!m_simpleKeyAllowed) + throw IllegalMapKey(); + + PushIndentTo(m_column, false); + } + + // TODO: "remove simple key" + + // can only put a simple key here if we're in block context + if(m_flowLevel == 0) + m_simpleKeyAllowed = true; + else + m_simpleKeyAllowed = false; + + // eat + INPUT.get(); + return pToken; + } + + // ValueToken + template <> ValueToken *Scanner::ScanToken(ValueToken *pToken) + { + // TODO: Is it a simple key? + if(false) { + } else { + // If not, ... + // are we in block context? + if(m_flowLevel == 0) { + if(!m_simpleKeyAllowed) + throw IllegalMapValue(); + + PushIndentTo(m_column, false); + } + } + + // can only put a simple key here if we're in block context + if(m_flowLevel == 0) + m_simpleKeyAllowed = true; + else + m_simpleKeyAllowed = false; + + // eat + INPUT.get(); + return pToken; + } + + // PlainScalarToken + template <> PlainScalarToken *Scanner::ScanToken(PlainScalarToken *pToken) + { + // TODO: "save simple key" + + m_simpleKeyAllowed = false; + + // now eat and store the scalar + while(1) { + // doc start/end tokens + if(IsDocumentStart() || IsDocumentEnd()) + break; + + // comment + if(INPUT.peek() == Keys::Comment) + break; + + // first eat non-blanks + while(!IsBlank()) { + // illegal colon in flow context + if(m_flowLevel > 0 && INPUT.peek() == ':') { + INPUT.get(); + if(!IsBlank()) { + INPUT.putback(':'); + throw IllegalScalar(); + } + INPUT.putback(':'); + } + + // characters that might end the scalar + // TODO: scanner.c line 3434 + } + } + + return pToken; + } + /////////////////////////////////////////////////////////////////////// // The main scanning function - Token *Scanner::ScanNextToken() + void Scanner::ScanNextToken() { if(!m_startedStream) - return ScanToken(new StreamStartToken); + return ScanAndEnqueue(new StreamStartToken); ScanToNextToken(); // TODO: remove "obsolete potential simple keys" - // TODO: unroll indent + PopIndentTo(m_column); if(INPUT.peek() == EOF) - return ScanToken(new StreamEndToken); + return ScanAndEnqueue(new StreamEndToken); + // are we at a document token? if(IsDocumentStart()) - return ScanToken(new DocumentStartToken); + return ScanAndEnqueue(new DocumentStartToken); if(IsDocumentEnd()) - return ScanToken(new DocumentEndToken); + return ScanAndEnqueue(new DocumentEndToken); - return 0; + // are we at a flow start/end/entry? + if(INPUT.peek() == Keys::FlowSeqStart) + return ScanAndEnqueue(new FlowSeqStartToken); + + if(INPUT.peek() == Keys::FlowSeqEnd) + return ScanAndEnqueue(new FlowSeqEndToken); + + if(INPUT.peek() == Keys::FlowMapStart) + return ScanAndEnqueue(new FlowMapStartToken); + + if(INPUT.peek() == Keys::FlowMapEnd) + return ScanAndEnqueue(new FlowMapEndToken); + + if(INPUT.peek() == Keys::FlowEntry) + return ScanAndEnqueue(new FlowEntryToken); + + // block/map stuff? + if(IsBlockEntry()) + return ScanAndEnqueue(new BlockEntryToken); + + if(IsKey()) + return ScanAndEnqueue(new KeyToken); + + if(IsValue()) + return ScanAndEnqueue(new ValueToken); + + // TODO: alias/anchor/tag + + // TODO: special scalars + if(INPUT.peek() == Keys::LiteralScalar && m_flowLevel == 0) + return; + + if(INPUT.peek() == Keys::FoldedScalar && m_flowLevel == 0) + return; + + if(INPUT.peek() == '\'') + return; + + if(INPUT.peek() == '\"') + return; + + // plain scalars + if(IsPlainScalar()) + return ScanAndEnqueue(new PlainScalarToken); + + // don't know what it is! + throw UnknownToken(); } // ScanToNextToken @@ -266,10 +611,47 @@ namespace YAML } } + // PushIndentTo + // . Pushes an indentation onto the stack, and enqueues the + // proper token (sequence start or mapping start). + void Scanner::PushIndentTo(int column, bool sequence) + { + // are we in flow? + if(m_flowLevel > 0) + return; + + // is this actually an indentation? + if(column <= m_indents.top()) + return; + + // now push + m_indents.push(column); + if(sequence) + m_tokens.push(new BlockSeqStartToken); + else + m_tokens.push(new BlockMapStartToken); + } + + // PopIndentTo + // . Pops indentations off the stack until we reach 'column' indentation, + // and enqueues the proper token each time. + void Scanner::PopIndentTo(int column) + { + // are we in flow? + if(m_flowLevel > 0) + return; + + // now pop away + while(!m_indents.empty() && m_indents.top() > column) { + m_indents.pop(); + m_tokens.push(new BlockEndToken); + } + } + // temporary function for testing void Scanner::Scan() { - while(Token *pToken = ScanNextToken()) - delete pToken; + while(INPUT) + ScanNextToken(); } } diff --git a/scanner.h b/scanner.h index 7fd8f5a..9d9e282 100644 --- a/scanner.h +++ b/scanner.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace YAML { @@ -12,6 +13,19 @@ namespace YAML namespace Keys { const char Comment = '#'; + const char FlowSeqStart = '['; + const char FlowSeqEnd = ']'; + const char FlowMapStart = '{'; + const char FlowMapEnd = '}'; + const char FlowEntry = ','; + const char BlockEntry = '-'; + const char Key = '?'; + const char Value = ':'; + const char Alias = '*'; + const char Anchor = '&'; + const char Tag = '!'; + const char LiteralScalar = '|'; + const char FoldedScalar = '>'; } class Scanner @@ -20,8 +34,10 @@ namespace YAML Scanner(std::istream& in); ~Scanner(); - Token *ScanNextToken(); + void ScanNextToken(); void ScanToNextToken(); + void PushIndentTo(int column, bool sequence); + void PopIndentTo(int column); void Scan(); @@ -36,6 +52,12 @@ namespace YAML bool IsBlank(); bool IsDocumentStart(); bool IsDocumentEnd(); + bool IsBlockEntry(); + bool IsKey(); + bool IsValue(); + bool IsPlainScalar(); + + template void ScanAndEnqueue(T *pToken); template T *ScanToken(T *pToken); private: @@ -45,6 +67,7 @@ namespace YAML // the output (tokens) std::queue m_tokens; + std::set m_limboTokens; // state info bool m_startedStream; diff --git a/token.h b/token.h index 699b93b..aab0af2 100644 --- a/token.h +++ b/token.h @@ -3,8 +3,25 @@ namespace YAML { class Token {}; + class StreamStartToken: public Token {}; class StreamEndToken: public Token {}; class DocumentStartToken: public Token {}; class DocumentEndToken: public Token {}; + + class BlockSeqStartToken: public Token {}; + class BlockMapStartToken: public Token {}; + class BlockEndToken: public Token {}; + class BlockEntryToken: public Token {}; + + class FlowSeqStartToken: public Token {}; + class FlowMapStartToken: public Token {}; + class FlowSeqEndToken: public Token {}; + class FlowMapEndToken: public Token {}; + class FlowEntryToken: public Token {}; + + class KeyToken: public Token {}; + class ValueToken: public Token {}; + + class PlainScalarToken: public Token {}; } diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index 88eb74d..04a440f 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -211,6 +211,10 @@ RelativePath=".\document.h" > + + From c7274ff2e8be63e60051c07f883a38ece4c22583 Mon Sep 17 00:00:00 2001 From: beder Date: Thu, 26 Jun 2008 22:00:39 +0000 Subject: [PATCH 008/295] More simple scalar scanning. --- document.cpp | 3 +- exceptions.h | 1 + scanner.cpp | 354 ++++++++++++++++++++++----------------------------- scanner.h | 13 +- token.h | 2 +- 5 files changed, 164 insertions(+), 209 deletions(-) diff --git a/document.cpp b/document.cpp index 8ba707d..2ae9cc9 100644 --- a/document.cpp +++ b/document.cpp @@ -36,8 +36,9 @@ namespace YAML try { scanner.Scan(); - } catch(const UnknownToken& e) { + } catch(const Exception& e) { } + getchar(); // if(!scanner) // return; diff --git a/exceptions.h b/exceptions.h index 947b924..2b4e689 100644 --- a/exceptions.h +++ b/exceptions.h @@ -11,4 +11,5 @@ namespace YAML class IllegalMapKey: public Exception {}; class IllegalMapValue: public Exception {}; class IllegalScalar: public Exception {}; + class IllegalTabInScalar: public Exception {}; } diff --git a/scanner.cpp b/scanner.cpp index 5320b29..8022742 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -1,6 +1,7 @@ #include "scanner.h" #include "token.h" #include "exceptions.h" +#include namespace YAML { @@ -32,30 +33,42 @@ namespace YAML return INPUT.get(); } + // Eat + // . Eats 'n' characters and updates our position. + void Scanner::Eat(int n) + { + for(int i=0;i=0;i--) + INPUT.putback(ret[i]); + + return ret; + } + // GetLineBreak // . Eats with no checking void Scanner::EatLineBreak() { + Eat(1); m_column = 0; - INPUT.get(); - } - - // EatDocumentStart - // . Eats with no checking - void Scanner::EatDocumentStart() - { - INPUT.get(); - INPUT.get(); - INPUT.get(); - } - - // EatDocumentEnd - // . Eats with no checking - void Scanner::EatDocumentEnd() - { - INPUT.get(); - INPUT.get(); - INPUT.get(); } // IsWhitespaceToBeEaten @@ -65,10 +78,8 @@ namespace YAML // a. In the flow context // b. In the block context but not where a simple key could be allowed // (i.e., not at the beginning of a line, or following '-', '?', or ':') - bool Scanner::IsWhitespaceToBeEaten() + bool Scanner::IsWhitespaceToBeEaten(char ch) { - char ch = INPUT.peek(); - if(ch == ' ') return true; @@ -79,17 +90,15 @@ namespace YAML } // IsLineBreak - bool Scanner::IsLineBreak() + bool Scanner::IsLineBreak(char ch) { - char ch = INPUT.peek(); return ch == '\n'; // TODO: More types of line breaks } // IsBlank - bool Scanner::IsBlank() + bool Scanner::IsBlank(char ch) { - char ch = INPUT.peek(); - return IsLineBreak() || ch == ' ' || ch == '\t' || ch == EOF; + return IsLineBreak(ch) || ch == ' ' || ch == '\t' || ch == EOF; } // IsDocumentStart @@ -99,34 +108,8 @@ namespace YAML if(m_column != 0) return false; - // then needs '---' - for(int i=0;i<3;i++) { - if(INPUT.peek() != '-') { - // first put 'em back - for(int j=0;j 0); } // IsValue bool Scanner::IsValue() { - if(INPUT.peek() != Keys::Value) - return false; - - INPUT.get(); - - // then needs a blank character (or eof), if we're in block context - if(m_flowLevel == 0 && !IsBlank()) { - INPUT.putback(Keys::BlockEntry); - return false; - } - - INPUT.putback(Keys::BlockEntry); - return true; + std::string next = Peek(2); + return next[0] == Keys::Value && (IsBlank(next[1]) || m_flowLevel > 0); } // IsPlainScalar @@ -228,34 +152,25 @@ namespace YAML // . In the flow context ? : are illegal and - must not be followed with a space. bool Scanner::IsPlainScalar() { - if(IsBlank()) + std::string next = Peek(2); + + if(IsBlank(next[0])) return false; // never characters - std::string never = ",[]{}#&*!|>\'\"%@`"; - for(unsigned i=0;i\'\"%@`").find(next[0]) != std::string::npos) + return false; // specific block/flow characters if(m_flowLevel == 0) { - if(INPUT.peek() == '-' || INPUT.peek() == '?' || INPUT.peek() == ':') { - char ch = INPUT.get(); - if(IsBlank()) { - INPUT.putback(ch); - return false; - } - } - } else { - if(INPUT.peek() == '?' || INPUT.peek() == ':') + if((next[0] == '-' || next[0] == '?' || next[0] == ':') && IsBlank(next[1])) + return false; + } else { + if(next[0] == '?' || next[0] == ':') + return false; + + if(next[0] == '-' && IsBlank(next[1])) return false; - if(INPUT.peek() == '-') { - INPUT.get(); - if(IsBlank()) { - INPUT.putback('-'); - return false; - } - } } return true; @@ -311,8 +226,8 @@ namespace YAML m_simpleKeyAllowed = false; - // eat it - EatDocumentStart(); + // eat + Eat(3); return pToken; } @@ -325,8 +240,8 @@ namespace YAML m_simpleKeyAllowed = false; - // eat it - EatDocumentEnd(); + // eat + Eat(3); return pToken; } @@ -419,7 +334,7 @@ namespace YAML m_simpleKeyAllowed = true; // eat - INPUT.get(); + Eat(1); return pToken; } @@ -443,7 +358,7 @@ namespace YAML m_simpleKeyAllowed = false; // eat - INPUT.get(); + Eat(1); return pToken; } @@ -453,61 +368,90 @@ namespace YAML // TODO: Is it a simple key? if(false) { } else { - // If not, ... - // are we in block context? - if(m_flowLevel == 0) { - if(!m_simpleKeyAllowed) - throw IllegalMapValue(); - - PushIndentTo(m_column, false); - } - } - + // If not, ... + // are we in block context? + if(m_flowLevel == 0) { + if(!m_simpleKeyAllowed) + throw IllegalMapValue(); + + PushIndentTo(m_column, false); + } + } + // can only put a simple key here if we're in block context if(m_flowLevel == 0) m_simpleKeyAllowed = true; else - m_simpleKeyAllowed = false; - - // eat - INPUT.get(); + m_simpleKeyAllowed = false; + + // eat + Eat(1); return pToken; } // PlainScalarToken template <> PlainScalarToken *Scanner::ScanToken(PlainScalarToken *pToken) - { - // TODO: "save simple key" - - m_simpleKeyAllowed = false; - - // now eat and store the scalar - while(1) { - // doc start/end tokens - if(IsDocumentStart() || IsDocumentEnd()) - break; - - // comment - if(INPUT.peek() == Keys::Comment) - break; - - // first eat non-blanks - while(!IsBlank()) { - // illegal colon in flow context - if(m_flowLevel > 0 && INPUT.peek() == ':') { - INPUT.get(); - if(!IsBlank()) { - INPUT.putback(':'); - throw IllegalScalar(); - } - INPUT.putback(':'); - } - - // characters that might end the scalar - // TODO: scanner.c line 3434 - } - } - + { + // TODO: "save simple key" + + m_simpleKeyAllowed = false; + + // now eat and store the scalar + std::string scalar; + bool leadingBlanks = true; + + while(INPUT) { + // doc start/end tokens + if(IsDocumentStart() || IsDocumentEnd()) + break; + + // comment + if(INPUT.peek() == Keys::Comment) + break; + + // first eat non-blanks + while(INPUT && !IsBlank(INPUT.peek())) { + std::string next = Peek(2); + + // illegal colon in flow context + if(m_flowLevel > 0 && next[0] == ':') { + if(!IsBlank(next[1])) + throw IllegalScalar(); + } + + // characters that might end the scalar + if(next[0] == ':' && IsBlank(next[1])) + break; + if(m_flowLevel > 0 && std::string(",:?[]{}").find(next[0]) != std::string::npos) + break; + + scalar += GetChar(); + } + + // now eat blanks + while(IsBlank(INPUT.peek()) /* || IsBreak(INPUT.peek()) */) { + if(IsBlank(INPUT.peek())) { + if(leadingBlanks && m_column <= m_indents.top()) + throw IllegalTabInScalar(); + + // TODO: Store some blanks? + Eat(1); + } else { + Eat(1); + } + } + + // TODO: join whitespace + + // and finally break if we're below the indentation level + if(m_flowLevel == 0 && m_column <= m_indents.top()) + break; + } + + // now modify our token + if(leadingBlanks) + m_simpleKeyAllowed = true; + return pToken; } @@ -588,18 +532,18 @@ namespace YAML { while(1) { // first eat whitespace - while(IsWhitespaceToBeEaten()) - INPUT.get(); + while(IsWhitespaceToBeEaten(INPUT.peek())) + Eat(1); // then eat a comment if(INPUT.peek() == Keys::Comment) { // eat until line break - while(INPUT && !IsLineBreak()) - INPUT.get(); + while(INPUT && !IsLineBreak(INPUT.peek())) + Eat(1); } // if it's NOT a line break, then we're done! - if(!IsLineBreak()) + if(!IsLineBreak(INPUT.peek())) break; // otherwise, let's eat the line break and keep going @@ -651,7 +595,15 @@ namespace YAML // temporary function for testing void Scanner::Scan() { - while(INPUT) + while(INPUT) { ScanNextToken(); + + while(!m_tokens.empty()) { + Token *pToken = m_tokens.front(); + m_tokens.pop(); + std::cout << typeid(*pToken).name() << std::endl; + delete pToken; + } + } } } diff --git a/scanner.h b/scanner.h index 9d9e282..1bc9e1a 100644 --- a/scanner.h +++ b/scanner.h @@ -43,13 +43,14 @@ namespace YAML private: char GetChar(); - void EatLineBreak(); - void EatDocumentStart(); - void EatDocumentEnd(); + void Eat(int n = 1); + std::string Peek(int n); - bool IsWhitespaceToBeEaten(); - bool IsLineBreak(); - bool IsBlank(); + void EatLineBreak(); + + bool IsWhitespaceToBeEaten(char ch); + bool IsLineBreak(char ch); + bool IsBlank(char ch); bool IsDocumentStart(); bool IsDocumentEnd(); bool IsBlockEntry(); diff --git a/token.h b/token.h index aab0af2..da3dfff 100644 --- a/token.h +++ b/token.h @@ -2,7 +2,7 @@ namespace YAML { - class Token {}; + class Token { public: virtual ~Token() {} }; class StreamStartToken: public Token {}; class StreamEndToken: public Token {}; From 20dba9cd752a31dbb8469831465ff50f722cbf12 Mon Sep 17 00:00:00 2001 From: beder Date: Fri, 27 Jun 2008 00:18:52 +0000 Subject: [PATCH 009/295] The plain scalar scanner is almost done (and it scans a simple list correctly). Also messed around with multiple character peeking on the input, and got something working. --- scanner.cpp | 50 ++++++++++++++++++++++++-------------------------- scanner.h | 2 +- test.yaml | 3 +-- token.h | 7 ++++++- 4 files changed, 32 insertions(+), 30 deletions(-) diff --git a/scanner.cpp b/scanner.cpp index 8022742..6fed538 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -6,7 +6,7 @@ namespace YAML { Scanner::Scanner(std::istream& in) - : INPUT(in), m_startedStream(false), m_simpleKeyAllowed(false), m_flowLevel(0), m_column(0) + : INPUT(in), m_startedStream(false), m_endedStream(false), m_simpleKeyAllowed(false), m_flowLevel(0), m_column(0) { } @@ -51,14 +51,12 @@ namespace YAML { std::string ret; - // extract n - 1 characters, and peek at the nth - for(int i=0;i=0;i--) - INPUT.putback(ret[i]); + INPUT.clear(); + INPUT.seekg(pos); return ret; } @@ -214,6 +212,7 @@ namespace YAML // TODO: "reset simple keys" m_simpleKeyAllowed = false; + m_endedStream = true; return pToken; } @@ -228,7 +227,6 @@ namespace YAML // eat Eat(3); - return pToken; } @@ -242,7 +240,6 @@ namespace YAML // eat Eat(3); - return pToken; } @@ -254,9 +251,8 @@ namespace YAML m_simpleKeyAllowed = true; - // eat it - INPUT.get(); - + // eat + Eat(1); return pToken; } @@ -268,9 +264,8 @@ namespace YAML m_simpleKeyAllowed = true; - // eat it - INPUT.get(); - + // eat + Eat(1); return pToken; } @@ -282,9 +277,8 @@ namespace YAML m_simpleKeyAllowed = false; - // eat it - INPUT.get(); - + // eat + Eat(1); return pToken; } @@ -296,9 +290,8 @@ namespace YAML m_simpleKeyAllowed = false; - // eat it - INPUT.get(); - + // eat + Eat(1); return pToken; } @@ -309,9 +302,8 @@ namespace YAML m_simpleKeyAllowed = true; - // eat it - INPUT.get(); - + // eat + Eat(1); return pToken; } @@ -429,7 +421,7 @@ namespace YAML } // now eat blanks - while(IsBlank(INPUT.peek()) /* || IsBreak(INPUT.peek()) */) { + while(INPUT && (IsBlank(INPUT.peek()) /* || IsBreak(INPUT.peek()) */)) { if(IsBlank(INPUT.peek())) { if(leadingBlanks && m_column <= m_indents.top()) throw IllegalTabInScalar(); @@ -449,6 +441,7 @@ namespace YAML } // now modify our token + pToken->SetValue(scalar); if(leadingBlanks) m_simpleKeyAllowed = true; @@ -460,6 +453,9 @@ namespace YAML void Scanner::ScanNextToken() { + if(m_endedStream) + return; + if(!m_startedStream) return ScanAndEnqueue(new StreamStartToken); @@ -595,8 +591,10 @@ namespace YAML // temporary function for testing void Scanner::Scan() { - while(INPUT) { + while(1) { ScanNextToken(); + if(m_tokens.empty()) + break; while(!m_tokens.empty()) { Token *pToken = m_tokens.front(); diff --git a/scanner.h b/scanner.h index 1bc9e1a..83f2583 100644 --- a/scanner.h +++ b/scanner.h @@ -71,7 +71,7 @@ namespace YAML std::set m_limboTokens; // state info - bool m_startedStream; + bool m_startedStream, m_endedStream; bool m_simpleKeyAllowed; int m_flowLevel; // number of unclosed '[' and '{' indicators std::stack m_indents; diff --git a/test.yaml b/test.yaml index 7ac0238..0581ec1 100644 --- a/test.yaml +++ b/test.yaml @@ -1,4 +1,3 @@ ---- - milk - eggs -- cheese \ No newline at end of file +- cheese and bread # this is really important! diff --git a/token.h b/token.h index da3dfff..ece11d8 100644 --- a/token.h +++ b/token.h @@ -23,5 +23,10 @@ namespace YAML class KeyToken: public Token {}; class ValueToken: public Token {}; - class PlainScalarToken: public Token {}; + class PlainScalarToken: public Token { + public: + void SetValue(const std::string& value) { m_value = value; } + protected: + std::string m_value; + }; } From bb4bc8c4aeb9de6570d51b195703003f123fa3fc Mon Sep 17 00:00:00 2001 From: beder Date: Fri, 27 Jun 2008 08:20:41 +0000 Subject: [PATCH 010/295] Wrote a simplified regular expression parser to make life easier (it only does single matches; i.e., no one-or-more matches, etc.). Fixed some of the whitespace/line break matching. --- main.cpp | 17 ++++++ regex.cpp | 114 ++++++++++++++++++++++++++++++++++++++ regex.h | 37 +++++++++++++ scanner.cpp | 133 ++++++++++++++++++++++----------------------- scanner.h | 37 +++++++++++-- test.yaml | 6 +- yaml-reader.vcproj | 8 +++ 7 files changed, 277 insertions(+), 75 deletions(-) create mode 100644 regex.cpp create mode 100644 regex.h diff --git a/main.cpp b/main.cpp index f5f3fa8..6ff8af6 100644 --- a/main.cpp +++ b/main.cpp @@ -1,7 +1,24 @@ #include "document.h" +#include "regex.h" int main() { + YAML::RegEx alpha = YAML::RegEx('a', 'z') || YAML::RegEx('A', 'Z'); + alpha.Matches("a"); + alpha.Matches("d"); + alpha.Matches("F"); + alpha.Matches("0"); + alpha.Matches("5"); + alpha.Matches(" "); + + YAML::RegEx blank = YAML::RegEx(' ') || YAML::RegEx('\t'); + YAML::RegEx docstart = YAML::RegEx("---") + (blank || YAML::RegEx(EOF) || YAML::RegEx()); + docstart.Matches("--- "); + docstart.Matches("... "); + docstart.Matches("----"); + docstart.Matches("---\t"); + docstart.Matches("---"); + YAML::Document doc("test.yaml"); return 0; diff --git a/regex.cpp b/regex.cpp new file mode 100644 index 0000000..a2907f5 --- /dev/null +++ b/regex.cpp @@ -0,0 +1,114 @@ +#include "regex.h" + +namespace YAML +{ + RegEx::RegEx(REGEX_OP op): m_op(op) + { + } + + RegEx::RegEx(): m_op(REGEX_EMPTY) + { + } + + RegEx::RegEx(char ch): m_op(REGEX_MATCH), m_a(ch) + { + } + + RegEx::RegEx(char a, char z): m_op(REGEX_RANGE), m_a(a), m_z(z) + { + } + + RegEx::RegEx(const std::string& str, REGEX_OP op): m_op(op) + { + for(unsigned i=0;i= 0; + } + + // Match + // . Matches the given string against this regular expression. + // . Returns the number of characters matched. + // . Returns -1 if no characters were matched (the reason for + // not returning zero is that we may have an empty regex + // which SHOULD be considered successfully matching nothing, + // but that of course matches zero characters). + int RegEx::Match(const std::string& str) const + { + switch(m_op) { + case REGEX_EMPTY: + if(str.empty()) + return 0; + return -1; + case REGEX_MATCH: + if(str.empty() || str[0] != m_a) + return -1; + return 1; + case REGEX_RANGE: + if(str.empty() || m_a > str[0] || m_z < str[0]) + return -1; + return 1; + case REGEX_NOT: + if(m_params.empty()) + return false; + if(m_params[0].Match(str) >= 0) + return -1; + return 1; + case REGEX_OR: + for(unsigned i=0;i= 0) + return n; + } + return -1; + case REGEX_SEQ: + int offset = 0; + for(unsigned i=0;i +#include + +namespace YAML +{ + enum REGEX_OP { REGEX_EMPTY, REGEX_MATCH, REGEX_RANGE, REGEX_OR, REGEX_NOT, REGEX_SEQ }; + + // simplified regular expressions + // . Only straightforward matches (no repeated characters) + // . Only matches from start of string + class RegEx { + public: + RegEx(); + RegEx(char ch); + RegEx(char a, char z); + RegEx(const std::string& str, REGEX_OP op = REGEX_SEQ); + ~RegEx(); + + bool Matches(char ch) const; + bool Matches(const std::string& str) const; + int Match(const std::string& str) const; + + friend RegEx operator ! (const RegEx& ex); + friend RegEx operator || (const RegEx& ex1, const RegEx& ex2); + friend RegEx operator + (const RegEx& ex1, const RegEx& ex2); + + private: + RegEx(REGEX_OP op); + + private: + REGEX_OP m_op; + char m_a, m_z; + std::vector m_params; + }; +} diff --git a/scanner.cpp b/scanner.cpp index 6fed538..e1495f5 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -30,7 +30,10 @@ namespace YAML char Scanner::GetChar() { m_column++; - return INPUT.get(); + char ch = INPUT.get(); + if(ch == '\n') + m_column = 0; + return ch; } // Eat @@ -87,18 +90,6 @@ namespace YAML return false; } - // IsLineBreak - bool Scanner::IsLineBreak(char ch) - { - return ch == '\n'; // TODO: More types of line breaks - } - - // IsBlank - bool Scanner::IsBlank(char ch) - { - return IsLineBreak(ch) || ch == ' ' || ch == '\t' || ch == EOF; - } - // IsDocumentStart bool Scanner::IsDocumentStart() { @@ -106,8 +97,7 @@ namespace YAML if(m_column != 0) return false; - std::string next = Peek(4); - return next[0] == '-' && next[1] == '-' && next[2] == '-' && IsBlank(next[3]); + return Exp::DocStart.Matches(Peek(4)); } // IsDocumentEnd @@ -117,61 +107,41 @@ namespace YAML if(m_column != 0) return false; - std::string next = Peek(4); - return next[0] == '.' && next[1] == '.' && next[2] == '.' && IsBlank(next[3]); + return Exp::DocEnd.Matches(Peek(4)); } // IsBlockEntry bool Scanner::IsBlockEntry() { - std::string next = Peek(2); - return next[0] == Keys::BlockEntry && IsBlank(next[1]); + return Exp::BlockEntry.Matches(Peek(2)); } // IsKey bool Scanner::IsKey() { std::string next = Peek(2); - return next[0] == Keys::Key && (IsBlank(next[1]) || m_flowLevel > 0); + if(m_flowLevel > 0) + return Exp::KeyInFlow.Matches(next); + return Exp::Key.Matches(next); } // IsValue bool Scanner::IsValue() { std::string next = Peek(2); - return next[0] == Keys::Value && (IsBlank(next[1]) || m_flowLevel > 0); + if(m_flowLevel > 0) + return Exp::ValueInFlow.Matches(next); + return Exp::Value.Matches(next); } // IsPlainScalar // . Rules: - // . Cannot start with a blank. - // . Can never start with any of , [ ] { } # & * ! | > \' \" % @ ` - // . In the block context - ? : must be not be followed with a space. - // . In the flow context ? : are illegal and - must not be followed with a space. bool Scanner::IsPlainScalar() { std::string next = Peek(2); - - if(IsBlank(next[0])) - return false; - - // never characters - if(std::string(",[]{}#&*!|>\'\"%@`").find(next[0]) != std::string::npos) - return false; - - // specific block/flow characters - if(m_flowLevel == 0) { - if((next[0] == '-' || next[0] == '?' || next[0] == ':') && IsBlank(next[1])) - return false; - } else { - if(next[0] == '?' || next[0] == ':') - return false; - - if(next[0] == '-' && IsBlank(next[1])) - return false; - } - - return true; + if(m_flowLevel > 0) + return Exp::PlainScalarInFlow.Matches(next); + return Exp::PlainScalar.Matches(next); } /////////////////////////////////////////////////////////////////////// @@ -233,7 +203,7 @@ namespace YAML // DocumentEndToken template <> DocumentEndToken *Scanner::ScanToken(DocumentEndToken *pToken) { - PopIndentTo(m_column); + PopIndentTo(-1); // TODO: "reset simple keys" m_simpleKeyAllowed = false; @@ -389,8 +359,8 @@ namespace YAML m_simpleKeyAllowed = false; // now eat and store the scalar - std::string scalar; - bool leadingBlanks = true; + std::string scalar, whitespace, leadingBreaks, trailingBreaks; + bool leadingBlanks = false; while(INPUT) { // doc start/end tokens @@ -398,43 +368,72 @@ namespace YAML break; // comment - if(INPUT.peek() == Keys::Comment) + if(Exp::Comment.Matches(INPUT.peek())) break; // first eat non-blanks - while(INPUT && !IsBlank(INPUT.peek())) { + while(INPUT && !Exp::BlankOrBreak.Matches(INPUT.peek())) { std::string next = Peek(2); // illegal colon in flow context - if(m_flowLevel > 0 && next[0] == ':') { - if(!IsBlank(next[1])) - throw IllegalScalar(); - } + if(m_flowLevel > 0 && Exp::IllegalColonInScalar.Matches(next)) + throw IllegalScalar(); // characters that might end the scalar - if(next[0] == ':' && IsBlank(next[1])) + if(m_flowLevel > 0 && Exp::EndScalarInFlow.Matches(next)) break; - if(m_flowLevel > 0 && std::string(",:?[]{}").find(next[0]) != std::string::npos) + if(m_flowLevel == 0 && Exp::EndScalar.Matches(next)) break; + if(leadingBlanks) { + if(!leadingBreaks.empty() && leadingBreaks[0] == '\n') { + // fold line break? + if(trailingBreaks.empty()) + scalar += ' '; + else { + scalar += trailingBreaks; + trailingBreaks = ""; + } + } else { + scalar += leadingBreaks + trailingBreaks; + leadingBreaks = ""; + trailingBreaks = ""; + } + } else if(!whitespace.empty()) { + scalar += whitespace; + whitespace = ""; + } + + // finally, read the character! scalar += GetChar(); } + // did we hit a non-blank character that ended us? + if(!Exp::BlankOrBreak.Matches(INPUT.peek())) + break; + // now eat blanks - while(INPUT && (IsBlank(INPUT.peek()) /* || IsBreak(INPUT.peek()) */)) { - if(IsBlank(INPUT.peek())) { + while(INPUT && Exp::BlankOrBreak.Matches(INPUT.peek())) { + if(Exp::Blank.Matches(INPUT.peek())) { if(leadingBlanks && m_column <= m_indents.top()) throw IllegalTabInScalar(); - // TODO: Store some blanks? - Eat(1); + // maybe store this character + if(!leadingBlanks) + whitespace += GetChar(); + else + Eat(1); } else { - Eat(1); + // where to store this character? + if(!leadingBlanks) { + leadingBlanks = true; + whitespace = ""; + leadingBreaks += GetChar(); + } else + trailingBreaks += GetChar(); } } - // TODO: join whitespace - // and finally break if we're below the indentation level if(m_flowLevel == 0 && m_column <= m_indents.top()) break; @@ -532,14 +531,14 @@ namespace YAML Eat(1); // then eat a comment - if(INPUT.peek() == Keys::Comment) { + if(Exp::Comment.Matches(INPUT.peek())) { // eat until line break - while(INPUT && !IsLineBreak(INPUT.peek())) + while(INPUT && !Exp::Break.Matches(INPUT.peek())) Eat(1); } // if it's NOT a line break, then we're done! - if(!IsLineBreak(INPUT.peek())) + if(!Exp::Break.Matches(INPUT.peek())) break; // otherwise, let's eat the line break and keep going diff --git a/scanner.h b/scanner.h index 83f2583..94cd88a 100644 --- a/scanner.h +++ b/scanner.h @@ -5,22 +5,49 @@ #include #include #include +#include "regex.h" namespace YAML { class Token; + namespace Exp + { + // misc + const RegEx Blank = RegEx(' ') || RegEx('\t'); + const RegEx Break = RegEx('\n'); + const RegEx BlankOrBreak = Blank || Break; + + // actual tags + + const RegEx DocStart = RegEx("---") + (BlankOrBreak || RegEx(EOF) || RegEx()); + const RegEx DocEnd = RegEx("...") + (BlankOrBreak || RegEx(EOF) || RegEx()); + const RegEx BlockEntry = RegEx('-') + (BlankOrBreak || RegEx(EOF)); + const RegEx Key = RegEx('?'), + KeyInFlow = RegEx('?') + BlankOrBreak; + const RegEx Value = RegEx(':'), + ValueInFlow = RegEx(':') + BlankOrBreak; + const RegEx Comment = RegEx('#'); + + // Plain scalar rules: + // . Cannot start with a blank. + // . Can never start with any of , [ ] { } # & * ! | > \' \" % @ ` + // . In the block context - ? : must be not be followed with a space. + // . In the flow context ? : are illegal and - must not be followed with a space. + const RegEx PlainScalar = !(BlankOrBreak || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:") + Blank)), + PlainScalarInFlow = !(BlankOrBreak || RegEx("?:,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx('-') + Blank)); + const RegEx IllegalColonInScalar = RegEx(':') + !BlankOrBreak; + const RegEx EndScalar = RegEx(':') + BlankOrBreak, + EndScalarInFlow = (RegEx(':') + BlankOrBreak) || RegEx(",:?[]{}"); + } + namespace Keys { - const char Comment = '#'; const char FlowSeqStart = '['; const char FlowSeqEnd = ']'; const char FlowMapStart = '{'; const char FlowMapEnd = '}'; const char FlowEntry = ','; - const char BlockEntry = '-'; - const char Key = '?'; - const char Value = ':'; const char Alias = '*'; const char Anchor = '&'; const char Tag = '!'; @@ -49,8 +76,6 @@ namespace YAML void EatLineBreak(); bool IsWhitespaceToBeEaten(char ch); - bool IsLineBreak(char ch); - bool IsBlank(char ch); bool IsDocumentStart(); bool IsDocumentEnd(); bool IsBlockEntry(); diff --git a/test.yaml b/test.yaml index 0581ec1..d3ad2c7 100644 --- a/test.yaml +++ b/test.yaml @@ -1,3 +1,5 @@ +--- - milk -- eggs -- cheese and bread # this is really important! +- eggs # this is really important! +- cheese and bread +... \ No newline at end of file diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index 04a440f..e0c32de 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -185,6 +185,10 @@ RelativePath=".\parser.cpp" > + + @@ -227,6 +231,10 @@ RelativePath=".\parser.h" > + + From aad36b8c478b600ad93dfc8314057ec4e73ad8a6 Mon Sep 17 00:00:00 2001 From: beder Date: Fri, 27 Jun 2008 19:07:30 +0000 Subject: [PATCH 011/295] Added stream input to the regular expressions, greatly simplifying the usage (in particular, we no longer have to specify the number of characters to be checked). --- regex.cpp | 214 +++++++++++++++++++++++++++++++++++++++++----------- regex.h | 45 ++++++++++- scanner.cpp | 56 +++++--------- scanner.h | 2 - 4 files changed, 232 insertions(+), 85 deletions(-) diff --git a/regex.cpp b/regex.cpp index a2907f5..f7830b7 100644 --- a/regex.cpp +++ b/regex.cpp @@ -2,30 +2,60 @@ namespace YAML { - RegEx::RegEx(REGEX_OP op): m_op(op) + RegEx::RegEx(REGEX_OP op): m_op(op), m_pOp(0) { + SetOp(); } - RegEx::RegEx(): m_op(REGEX_EMPTY) + RegEx::RegEx(const RegEx& rhs): m_pOp(0) { + m_op = rhs.m_op; + m_a = rhs.m_a; + m_z = rhs.m_z; + m_params = rhs.m_params; + + SetOp(); } - RegEx::RegEx(char ch): m_op(REGEX_MATCH), m_a(ch) + RegEx::RegEx(): m_op(REGEX_EMPTY), m_pOp(0) { + SetOp(); } - RegEx::RegEx(char a, char z): m_op(REGEX_RANGE), m_a(a), m_z(z) + RegEx::RegEx(char ch): m_op(REGEX_MATCH), m_pOp(0), m_a(ch) { + SetOp(); } - RegEx::RegEx(const std::string& str, REGEX_OP op): m_op(op) + RegEx::RegEx(char a, char z): m_op(REGEX_RANGE), m_pOp(0), m_a(a), m_z(z) + { + SetOp(); + } + + RegEx::RegEx(const std::string& str, REGEX_OP op): m_op(op), m_pOp(0) { for(unsigned i=0;i= 0; } + bool RegEx::Matches(std::istream& in) const + { + return Match(in) >= 0; + } + // Match // . Matches the given string against this regular expression. // . Returns the number of characters matched. @@ -49,44 +84,36 @@ namespace YAML // but that of course matches zero characters). int RegEx::Match(const std::string& str) const { - switch(m_op) { - case REGEX_EMPTY: - if(str.empty()) - return 0; - return -1; - case REGEX_MATCH: - if(str.empty() || str[0] != m_a) - return -1; - return 1; - case REGEX_RANGE: - if(str.empty() || m_a > str[0] || m_z < str[0]) - return -1; - return 1; - case REGEX_NOT: - if(m_params.empty()) - return false; - if(m_params[0].Match(str) >= 0) - return -1; - return 1; - case REGEX_OR: - for(unsigned i=0;i= 0) - return n; - } - return -1; - case REGEX_SEQ: - int offset = 0; - for(unsigned i=0;iMatch(str, *this); + + //case REGEX_EMPTY: + // if(str.empty()) + // return 0; + // return -1; + } + + // Match + // . The stream version does the same thing as the string version; + // REMEMBER that we only match from the start of the stream! + // . Note: the istream is not a const reference, but we guarantee + // that the pointer will be in the same spot, and we'll clear its + // flags before we end. + int RegEx::Match(std::istream& in) const + { + if(!m_pOp) + return -1; + + int pos = in.tellg(); + int ret = m_pOp->Match(in, *this); + + // reset input stream! + in.clear(); + in.seekg(pos); + + return ret; } RegEx operator ! (const RegEx& ex) @@ -111,4 +138,107 @@ namespace YAML ret.m_params.push_back(ex2); return ret; } + + ////////////////////////////////////////////////////////////////////////////// + // Operators + + // MatchOperator + int RegEx::MatchOperator::Match(const std::string& str, const RegEx& regex) const + { + if(str.empty() || str[0] != regex.m_a) + return -1; + return 1; + } + + + int RegEx::MatchOperator::Match(std::istream& in, const RegEx& regex) const + { + if(!in || in.peek() != regex.m_a) + return -1; + return 1; + } + + // RangeOperator + int RegEx::RangeOperator::Match(const std::string& str, const RegEx& regex) const + { + if(str.empty() || regex.m_a > str[0] || regex.m_z < str[0]) + return -1; + return 1; + } + + int RegEx::RangeOperator::Match(std::istream& in, const RegEx& regex) const + { + if(!in || regex.m_a > in.peek() || regex.m_z < in.peek()) + return -1; + return 1; + } + + // OrOperator + int RegEx::OrOperator::Match(const std::string& str, const RegEx& regex) const + { + for(unsigned i=0;i= 0) + return n; + } + return -1; + } + + int RegEx::OrOperator::Match(std::istream& in, const RegEx& regex) const + { + for(unsigned i=0;i= 0) + return n; + } + return -1; + } + + // NotOperator + int RegEx::NotOperator::Match(const std::string& str, const RegEx& regex) const + { + if(regex.m_params.empty()) + return -1; + if(regex.m_params[0].Match(str) >= 0) + return -1; + return 1; + } + + int RegEx::NotOperator::Match(std::istream& in, const RegEx& regex) const + { + if(regex.m_params.empty()) + return -1; + if(regex.m_params[0].Match(in) >= 0) + return -1; + return 1; + } + + // SeqOperator + int RegEx::SeqOperator::Match(const std::string& str, const RegEx& regex) const + { + int offset = 0; + for(unsigned i=0;i #include +#include namespace YAML { @@ -10,17 +11,55 @@ namespace YAML // simplified regular expressions // . Only straightforward matches (no repeated characters) // . Only matches from start of string - class RegEx { + class RegEx + { + private: + struct Operator { + virtual ~Operator() {} + virtual int Match(const std::string& str, const RegEx& regex) const = 0; + virtual int Match(std::istream& in, const RegEx& regex) const = 0; + }; + + struct MatchOperator: public Operator { + virtual int Match(const std::string& str, const RegEx& regex) const; + virtual int Match(std::istream& in, const RegEx& regex) const; + }; + + struct RangeOperator: public Operator { + virtual int Match(const std::string& str, const RegEx& regex) const; + virtual int Match(std::istream& in, const RegEx& regex) const; + }; + + struct OrOperator: public Operator { + virtual int Match(const std::string& str, const RegEx& regex) const; + virtual int Match(std::istream& in, const RegEx& regex) const; + }; + + struct NotOperator: public Operator { + virtual int Match(const std::string& str, const RegEx& regex) const; + virtual int Match(std::istream& in, const RegEx& regex) const; + }; + + struct SeqOperator: public Operator { + virtual int Match(const std::string& str, const RegEx& regex) const; + virtual int Match(std::istream& in, const RegEx& regex) const; + }; + public: + friend struct Operator; + RegEx(); RegEx(char ch); RegEx(char a, char z); - RegEx(const std::string& str, REGEX_OP op = REGEX_SEQ); + RegEx(const std::string& str, REGEX_OP op = REGEX_SEQ); + RegEx(const RegEx& rhs); ~RegEx(); bool Matches(char ch) const; bool Matches(const std::string& str) const; + bool Matches(std::istream& in) const; int Match(const std::string& str) const; + int Match(std::istream& in) const; friend RegEx operator ! (const RegEx& ex); friend RegEx operator || (const RegEx& ex1, const RegEx& ex2); @@ -28,9 +67,11 @@ namespace YAML private: RegEx(REGEX_OP op); + void SetOp(); private: REGEX_OP m_op; + Operator *m_pOp; char m_a, m_z; std::vector m_params; }; diff --git a/scanner.cpp b/scanner.cpp index e1495f5..f656d32 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -48,22 +48,6 @@ namespace YAML } } - // Peek - // . Peeks at the next 'n' characters and returns them in a string. - std::string Scanner::Peek(int n) - { - std::string ret; - - int pos = INPUT.tellg(); - for(int i=0;i 0) - return Exp::KeyInFlow.Matches(next); - return Exp::Key.Matches(next); + return Exp::KeyInFlow.Matches(INPUT); + return Exp::Key.Matches(INPUT); } // IsValue bool Scanner::IsValue() { - std::string next = Peek(2); if(m_flowLevel > 0) - return Exp::ValueInFlow.Matches(next); - return Exp::Value.Matches(next); + return Exp::ValueInFlow.Matches(INPUT); + return Exp::Value.Matches(INPUT); } // IsPlainScalar - // . Rules: bool Scanner::IsPlainScalar() { - std::string next = Peek(2); if(m_flowLevel > 0) - return Exp::PlainScalarInFlow.Matches(next); - return Exp::PlainScalar.Matches(next); + return Exp::PlainScalarInFlow.Matches(INPUT); + return Exp::PlainScalar.Matches(INPUT); } /////////////////////////////////////////////////////////////////////// @@ -368,21 +348,19 @@ namespace YAML break; // comment - if(Exp::Comment.Matches(INPUT.peek())) + if(Exp::Comment.Matches(INPUT)) break; // first eat non-blanks - while(INPUT && !Exp::BlankOrBreak.Matches(INPUT.peek())) { - std::string next = Peek(2); - + while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) { // illegal colon in flow context - if(m_flowLevel > 0 && Exp::IllegalColonInScalar.Matches(next)) + if(m_flowLevel > 0 && Exp::IllegalColonInScalar.Matches(INPUT)) throw IllegalScalar(); // characters that might end the scalar - if(m_flowLevel > 0 && Exp::EndScalarInFlow.Matches(next)) + if(m_flowLevel > 0 && Exp::EndScalarInFlow.Matches(INPUT)) break; - if(m_flowLevel == 0 && Exp::EndScalar.Matches(next)) + if(m_flowLevel == 0 && Exp::EndScalar.Matches(INPUT)) break; if(leadingBlanks) { @@ -409,12 +387,12 @@ namespace YAML } // did we hit a non-blank character that ended us? - if(!Exp::BlankOrBreak.Matches(INPUT.peek())) + if(!Exp::BlankOrBreak.Matches(INPUT)) break; // now eat blanks - while(INPUT && Exp::BlankOrBreak.Matches(INPUT.peek())) { - if(Exp::Blank.Matches(INPUT.peek())) { + while(INPUT && Exp::BlankOrBreak.Matches(INPUT)) { + if(Exp::Blank.Matches(INPUT)) { if(leadingBlanks && m_column <= m_indents.top()) throw IllegalTabInScalar(); diff --git a/scanner.h b/scanner.h index 94cd88a..4a91e50 100644 --- a/scanner.h +++ b/scanner.h @@ -71,8 +71,6 @@ namespace YAML private: char GetChar(); void Eat(int n = 1); - std::string Peek(int n); - void EatLineBreak(); bool IsWhitespaceToBeEaten(char ch); From 10c4a2687faebea03a1700aa9ff99b364a28dea6 Mon Sep 17 00:00:00 2001 From: beder Date: Fri, 27 Jun 2008 19:13:03 +0000 Subject: [PATCH 012/295] Split off the specific regular expressions, and the specialized token-scanning functions, into their own files. --- exp.h | 53 ++++++++ scanner.cpp | 288 +------------------------------------------- scanner.h | 45 ------- scantoken.cpp | 294 +++++++++++++++++++++++++++++++++++++++++++++ yaml-reader.vcproj | 8 ++ 5 files changed, 356 insertions(+), 332 deletions(-) create mode 100644 exp.h create mode 100644 scantoken.cpp diff --git a/exp.h b/exp.h new file mode 100644 index 0000000..bc2c59b --- /dev/null +++ b/exp.h @@ -0,0 +1,53 @@ +#pragma once + +#include "regex.h" + +namespace YAML +{ + //////////////////////////////////////////////////////////////////////////////// + // Here we store a bunch of expressions for matching different parts of the file. + + namespace Exp + { + // misc + const RegEx Blank = RegEx(' ') || RegEx('\t'); + const RegEx Break = RegEx('\n'); + const RegEx BlankOrBreak = Blank || Break; + + // actual tags + + const RegEx DocStart = RegEx("---") + (BlankOrBreak || RegEx(EOF) || RegEx()); + const RegEx DocEnd = RegEx("...") + (BlankOrBreak || RegEx(EOF) || RegEx()); + const RegEx BlockEntry = RegEx('-') + (BlankOrBreak || RegEx(EOF)); + const RegEx Key = RegEx('?'), + KeyInFlow = RegEx('?') + BlankOrBreak; + const RegEx Value = RegEx(':'), + ValueInFlow = RegEx(':') + BlankOrBreak; + const RegEx Comment = RegEx('#'); + + // Plain scalar rules: + // . Cannot start with a blank. + // . Can never start with any of , [ ] { } # & * ! | > \' \" % @ ` + // . In the block context - ? : must be not be followed with a space. + // . In the flow context ? : are illegal and - must not be followed with a space. + const RegEx PlainScalar = !(BlankOrBreak || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:") + Blank)), + PlainScalarInFlow = !(BlankOrBreak || RegEx("?:,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx('-') + Blank)); + const RegEx IllegalColonInScalar = RegEx(':') + !BlankOrBreak; + const RegEx EndScalar = RegEx(':') + BlankOrBreak, + EndScalarInFlow = (RegEx(':') + BlankOrBreak) || RegEx(",:?[]{}"); + } + + namespace Keys + { + const char FlowSeqStart = '['; + const char FlowSeqEnd = ']'; + const char FlowMapStart = '{'; + const char FlowMapEnd = '}'; + const char FlowEntry = ','; + const char Alias = '*'; + const char Anchor = '&'; + const char Tag = '!'; + const char LiteralScalar = '|'; + const char FoldedScalar = '>'; + } +} diff --git a/scanner.cpp b/scanner.cpp index f656d32..7f49977 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -1,6 +1,7 @@ #include "scanner.h" #include "token.h" #include "exceptions.h" +#include "exp.h" #include namespace YAML @@ -124,9 +125,6 @@ namespace YAML return Exp::PlainScalar.Matches(INPUT); } - /////////////////////////////////////////////////////////////////////// - // Specialization for scanning specific tokens - // ScanAndEnqueue // . Scans the token, then pushes it in the queue. // . Note: we also use a set of "limbo tokens", i.e., tokens @@ -141,290 +139,6 @@ namespace YAML m_limboTokens.erase(pToken); } - // StreamStartToken - template <> StreamStartToken *Scanner::ScanToken(StreamStartToken *pToken) - { - m_startedStream = true; - m_simpleKeyAllowed = true; - m_indents.push(-1); - - return pToken; - } - - // StreamEndToken - template <> StreamEndToken *Scanner::ScanToken(StreamEndToken *pToken) - { - // force newline - if(m_column > 0) - m_column = 0; - - PopIndentTo(-1); - // TODO: "reset simple keys" - - m_simpleKeyAllowed = false; - m_endedStream = true; - - return pToken; - } - - // DocumentStartToken - template <> DocumentStartToken *Scanner::ScanToken(DocumentStartToken *pToken) - { - PopIndentTo(m_column); - // TODO: "reset simple keys" - - m_simpleKeyAllowed = false; - - // eat - Eat(3); - return pToken; - } - - // DocumentEndToken - template <> DocumentEndToken *Scanner::ScanToken(DocumentEndToken *pToken) - { - PopIndentTo(-1); - // TODO: "reset simple keys" - - m_simpleKeyAllowed = false; - - // eat - Eat(3); - return pToken; - } - - // FlowSeqStartToken - template <> FlowSeqStartToken *Scanner::ScanToken(FlowSeqStartToken *pToken) - { - // TODO: "save simple key" - // TODO: increase flow level - - m_simpleKeyAllowed = true; - - // eat - Eat(1); - return pToken; - } - - // FlowMapStartToken - template <> FlowMapStartToken *Scanner::ScanToken(FlowMapStartToken *pToken) - { - // TODO: "save simple key" - // TODO: increase flow level - - m_simpleKeyAllowed = true; - - // eat - Eat(1); - return pToken; - } - - // FlowSeqEndToken - template <> FlowSeqEndToken *Scanner::ScanToken(FlowSeqEndToken *pToken) - { - // TODO: "remove simple key" - // TODO: decrease flow level - - m_simpleKeyAllowed = false; - - // eat - Eat(1); - return pToken; - } - - // FlowMapEndToken - template <> FlowMapEndToken *Scanner::ScanToken(FlowMapEndToken *pToken) - { - // TODO: "remove simple key" - // TODO: decrease flow level - - m_simpleKeyAllowed = false; - - // eat - Eat(1); - return pToken; - } - - // FlowEntryToken - template <> FlowEntryToken *Scanner::ScanToken(FlowEntryToken *pToken) - { - // TODO: "remove simple key" - - m_simpleKeyAllowed = true; - - // eat - Eat(1); - return pToken; - } - - // BlockEntryToken - template <> BlockEntryToken *Scanner::ScanToken(BlockEntryToken *pToken) - { - // we better be in the block context! - if(m_flowLevel == 0) { - // can we put it here? - if(!m_simpleKeyAllowed) - throw IllegalBlockEntry(); - - PushIndentTo(m_column, true); // , -1 - } else { - // TODO: throw? - } - - // TODO: "remove simple key" - - m_simpleKeyAllowed = true; - - // eat - Eat(1); - return pToken; - } - - // KeyToken - template <> KeyToken *Scanner::ScanToken(KeyToken *pToken) - { - // are we in block context? - if(m_flowLevel == 0) { - if(!m_simpleKeyAllowed) - throw IllegalMapKey(); - - PushIndentTo(m_column, false); - } - - // TODO: "remove simple key" - - // can only put a simple key here if we're in block context - if(m_flowLevel == 0) - m_simpleKeyAllowed = true; - else - m_simpleKeyAllowed = false; - - // eat - Eat(1); - return pToken; - } - - // ValueToken - template <> ValueToken *Scanner::ScanToken(ValueToken *pToken) - { - // TODO: Is it a simple key? - if(false) { - } else { - // If not, ... - // are we in block context? - if(m_flowLevel == 0) { - if(!m_simpleKeyAllowed) - throw IllegalMapValue(); - - PushIndentTo(m_column, false); - } - } - - // can only put a simple key here if we're in block context - if(m_flowLevel == 0) - m_simpleKeyAllowed = true; - else - m_simpleKeyAllowed = false; - - // eat - Eat(1); - return pToken; - } - - // PlainScalarToken - template <> PlainScalarToken *Scanner::ScanToken(PlainScalarToken *pToken) - { - // TODO: "save simple key" - - m_simpleKeyAllowed = false; - - // now eat and store the scalar - std::string scalar, whitespace, leadingBreaks, trailingBreaks; - bool leadingBlanks = false; - - while(INPUT) { - // doc start/end tokens - if(IsDocumentStart() || IsDocumentEnd()) - break; - - // comment - if(Exp::Comment.Matches(INPUT)) - break; - - // first eat non-blanks - while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) { - // illegal colon in flow context - if(m_flowLevel > 0 && Exp::IllegalColonInScalar.Matches(INPUT)) - throw IllegalScalar(); - - // characters that might end the scalar - if(m_flowLevel > 0 && Exp::EndScalarInFlow.Matches(INPUT)) - break; - if(m_flowLevel == 0 && Exp::EndScalar.Matches(INPUT)) - break; - - if(leadingBlanks) { - if(!leadingBreaks.empty() && leadingBreaks[0] == '\n') { - // fold line break? - if(trailingBreaks.empty()) - scalar += ' '; - else { - scalar += trailingBreaks; - trailingBreaks = ""; - } - } else { - scalar += leadingBreaks + trailingBreaks; - leadingBreaks = ""; - trailingBreaks = ""; - } - } else if(!whitespace.empty()) { - scalar += whitespace; - whitespace = ""; - } - - // finally, read the character! - scalar += GetChar(); - } - - // did we hit a non-blank character that ended us? - if(!Exp::BlankOrBreak.Matches(INPUT)) - break; - - // now eat blanks - while(INPUT && Exp::BlankOrBreak.Matches(INPUT)) { - if(Exp::Blank.Matches(INPUT)) { - if(leadingBlanks && m_column <= m_indents.top()) - throw IllegalTabInScalar(); - - // maybe store this character - if(!leadingBlanks) - whitespace += GetChar(); - else - Eat(1); - } else { - // where to store this character? - if(!leadingBlanks) { - leadingBlanks = true; - whitespace = ""; - leadingBreaks += GetChar(); - } else - trailingBreaks += GetChar(); - } - } - - // and finally break if we're below the indentation level - if(m_flowLevel == 0 && m_column <= m_indents.top()) - break; - } - - // now modify our token - pToken->SetValue(scalar); - if(leadingBlanks) - m_simpleKeyAllowed = true; - - return pToken; - } - /////////////////////////////////////////////////////////////////////// // The main scanning function diff --git a/scanner.h b/scanner.h index 4a91e50..29d6b42 100644 --- a/scanner.h +++ b/scanner.h @@ -5,56 +5,11 @@ #include #include #include -#include "regex.h" namespace YAML { class Token; - namespace Exp - { - // misc - const RegEx Blank = RegEx(' ') || RegEx('\t'); - const RegEx Break = RegEx('\n'); - const RegEx BlankOrBreak = Blank || Break; - - // actual tags - - const RegEx DocStart = RegEx("---") + (BlankOrBreak || RegEx(EOF) || RegEx()); - const RegEx DocEnd = RegEx("...") + (BlankOrBreak || RegEx(EOF) || RegEx()); - const RegEx BlockEntry = RegEx('-') + (BlankOrBreak || RegEx(EOF)); - const RegEx Key = RegEx('?'), - KeyInFlow = RegEx('?') + BlankOrBreak; - const RegEx Value = RegEx(':'), - ValueInFlow = RegEx(':') + BlankOrBreak; - const RegEx Comment = RegEx('#'); - - // Plain scalar rules: - // . Cannot start with a blank. - // . Can never start with any of , [ ] { } # & * ! | > \' \" % @ ` - // . In the block context - ? : must be not be followed with a space. - // . In the flow context ? : are illegal and - must not be followed with a space. - const RegEx PlainScalar = !(BlankOrBreak || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:") + Blank)), - PlainScalarInFlow = !(BlankOrBreak || RegEx("?:,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx('-') + Blank)); - const RegEx IllegalColonInScalar = RegEx(':') + !BlankOrBreak; - const RegEx EndScalar = RegEx(':') + BlankOrBreak, - EndScalarInFlow = (RegEx(':') + BlankOrBreak) || RegEx(",:?[]{}"); - } - - namespace Keys - { - const char FlowSeqStart = '['; - const char FlowSeqEnd = ']'; - const char FlowMapStart = '{'; - const char FlowMapEnd = '}'; - const char FlowEntry = ','; - const char Alias = '*'; - const char Anchor = '&'; - const char Tag = '!'; - const char LiteralScalar = '|'; - const char FoldedScalar = '>'; - } - class Scanner { public: diff --git a/scantoken.cpp b/scantoken.cpp new file mode 100644 index 0000000..0fd1179 --- /dev/null +++ b/scantoken.cpp @@ -0,0 +1,294 @@ +#include "scanner.h" +#include "token.h" +#include "exceptions.h" +#include "exp.h" + +namespace YAML +{ + /////////////////////////////////////////////////////////////////////// + // Specialization for scanning specific tokens + + // StreamStartToken + template <> StreamStartToken *Scanner::ScanToken(StreamStartToken *pToken) + { + m_startedStream = true; + m_simpleKeyAllowed = true; + m_indents.push(-1); + + return pToken; + } + + // StreamEndToken + template <> StreamEndToken *Scanner::ScanToken(StreamEndToken *pToken) + { + // force newline + if(m_column > 0) + m_column = 0; + + PopIndentTo(-1); + // TODO: "reset simple keys" + + m_simpleKeyAllowed = false; + m_endedStream = true; + + return pToken; + } + + // DocumentStartToken + template <> DocumentStartToken *Scanner::ScanToken(DocumentStartToken *pToken) + { + PopIndentTo(m_column); + // TODO: "reset simple keys" + + m_simpleKeyAllowed = false; + + // eat + Eat(3); + return pToken; + } + + // DocumentEndToken + template <> DocumentEndToken *Scanner::ScanToken(DocumentEndToken *pToken) + { + PopIndentTo(-1); + // TODO: "reset simple keys" + + m_simpleKeyAllowed = false; + + // eat + Eat(3); + return pToken; + } + + // FlowSeqStartToken + template <> FlowSeqStartToken *Scanner::ScanToken(FlowSeqStartToken *pToken) + { + // TODO: "save simple key" + // TODO: increase flow level + + m_simpleKeyAllowed = true; + + // eat + Eat(1); + return pToken; + } + + // FlowMapStartToken + template <> FlowMapStartToken *Scanner::ScanToken(FlowMapStartToken *pToken) + { + // TODO: "save simple key" + // TODO: increase flow level + + m_simpleKeyAllowed = true; + + // eat + Eat(1); + return pToken; + } + + // FlowSeqEndToken + template <> FlowSeqEndToken *Scanner::ScanToken(FlowSeqEndToken *pToken) + { + // TODO: "remove simple key" + // TODO: decrease flow level + + m_simpleKeyAllowed = false; + + // eat + Eat(1); + return pToken; + } + + // FlowMapEndToken + template <> FlowMapEndToken *Scanner::ScanToken(FlowMapEndToken *pToken) + { + // TODO: "remove simple key" + // TODO: decrease flow level + + m_simpleKeyAllowed = false; + + // eat + Eat(1); + return pToken; + } + + // FlowEntryToken + template <> FlowEntryToken *Scanner::ScanToken(FlowEntryToken *pToken) + { + // TODO: "remove simple key" + + m_simpleKeyAllowed = true; + + // eat + Eat(1); + return pToken; + } + + // BlockEntryToken + template <> BlockEntryToken *Scanner::ScanToken(BlockEntryToken *pToken) + { + // we better be in the block context! + if(m_flowLevel == 0) { + // can we put it here? + if(!m_simpleKeyAllowed) + throw IllegalBlockEntry(); + + PushIndentTo(m_column, true); // , -1 + } else { + // TODO: throw? + } + + // TODO: "remove simple key" + + m_simpleKeyAllowed = true; + + // eat + Eat(1); + return pToken; + } + + // KeyToken + template <> KeyToken *Scanner::ScanToken(KeyToken *pToken) + { + // are we in block context? + if(m_flowLevel == 0) { + if(!m_simpleKeyAllowed) + throw IllegalMapKey(); + + PushIndentTo(m_column, false); + } + + // TODO: "remove simple key" + + // can only put a simple key here if we're in block context + if(m_flowLevel == 0) + m_simpleKeyAllowed = true; + else + m_simpleKeyAllowed = false; + + // eat + Eat(1); + return pToken; + } + + // ValueToken + template <> ValueToken *Scanner::ScanToken(ValueToken *pToken) + { + // TODO: Is it a simple key? + if(false) { + } else { + // If not, ... + // are we in block context? + if(m_flowLevel == 0) { + if(!m_simpleKeyAllowed) + throw IllegalMapValue(); + + PushIndentTo(m_column, false); + } + } + + // can only put a simple key here if we're in block context + if(m_flowLevel == 0) + m_simpleKeyAllowed = true; + else + m_simpleKeyAllowed = false; + + // eat + Eat(1); + return pToken; + } + + // PlainScalarToken + template <> PlainScalarToken *Scanner::ScanToken(PlainScalarToken *pToken) + { + // TODO: "save simple key" + + m_simpleKeyAllowed = false; + + // now eat and store the scalar + std::string scalar, whitespace, leadingBreaks, trailingBreaks; + bool leadingBlanks = false; + + while(INPUT) { + // doc start/end tokens + if(IsDocumentStart() || IsDocumentEnd()) + break; + + // comment + if(Exp::Comment.Matches(INPUT)) + break; + + // first eat non-blanks + while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) { + // illegal colon in flow context + if(m_flowLevel > 0 && Exp::IllegalColonInScalar.Matches(INPUT)) + throw IllegalScalar(); + + // characters that might end the scalar + if(m_flowLevel > 0 && Exp::EndScalarInFlow.Matches(INPUT)) + break; + if(m_flowLevel == 0 && Exp::EndScalar.Matches(INPUT)) + break; + + if(leadingBlanks) { + if(!leadingBreaks.empty() && leadingBreaks[0] == '\n') { + // fold line break? + if(trailingBreaks.empty()) + scalar += ' '; + else { + scalar += trailingBreaks; + trailingBreaks = ""; + } + } else { + scalar += leadingBreaks + trailingBreaks; + leadingBreaks = ""; + trailingBreaks = ""; + } + } else if(!whitespace.empty()) { + scalar += whitespace; + whitespace = ""; + } + + // finally, read the character! + scalar += GetChar(); + } + + // did we hit a non-blank character that ended us? + if(!Exp::BlankOrBreak.Matches(INPUT)) + break; + + // now eat blanks + while(INPUT && Exp::BlankOrBreak.Matches(INPUT)) { + if(Exp::Blank.Matches(INPUT)) { + if(leadingBlanks && m_column <= m_indents.top()) + throw IllegalTabInScalar(); + + // maybe store this character + if(!leadingBlanks) + whitespace += GetChar(); + else + Eat(1); + } else { + // where to store this character? + if(!leadingBlanks) { + leadingBlanks = true; + whitespace = ""; + leadingBreaks += GetChar(); + } else + trailingBreaks += GetChar(); + } + } + + // and finally break if we're below the indentation level + if(m_flowLevel == 0 && m_column <= m_indents.top()) + break; + } + + // now modify our token + pToken->SetValue(scalar); + if(leadingBlanks) + m_simpleKeyAllowed = true; + + return pToken; + } +} diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index e0c32de..39f42a4 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -197,6 +197,10 @@ RelativePath=".\scanner.cpp" > + + @@ -219,6 +223,10 @@ RelativePath=".\exceptions.h" > + + From ba132b01bc9d637e800723b5303c0dbfa0de7277 Mon Sep 17 00:00:00 2001 From: beder Date: Fri, 27 Jun 2008 20:54:43 +0000 Subject: [PATCH 013/295] Small plain scalar scanning fixes. --- document.cpp | 5 +---- scanner.cpp | 19 +++++++++++------ scanner.h | 3 ++- scantoken.cpp | 36 +++++++++++++++++++++++--------- test.yaml | 9 ++++++-- token.h | 58 +++++++++++++++++++++++++++++---------------------- 6 files changed, 82 insertions(+), 48 deletions(-) diff --git a/document.cpp b/document.cpp index 2ae9cc9..ca07e66 100644 --- a/document.cpp +++ b/document.cpp @@ -34,10 +34,7 @@ namespace YAML std::ifstream fin(fileName.c_str()); Scanner scanner(fin); - try { - scanner.Scan(); - } catch(const Exception& e) { - } + scanner.Scan(); getchar(); // if(!scanner) // return; diff --git a/scanner.cpp b/scanner.cpp index 7f49977..19695bb 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -37,6 +37,16 @@ namespace YAML return ch; } + // GetChar + // . Extracts 'n' characters from the stream and updates our position + std::string Scanner::GetChar(int n) + { + std::string ret; + for(int i=0;i PlainScalarToken *Scanner::ScanToken(PlainScalarToken *pToken) { // TODO: "save simple key" @@ -230,20 +234,21 @@ namespace YAML if(m_flowLevel == 0 && Exp::EndScalar.Matches(INPUT)) break; + // join whitespace if(leadingBlanks) { - if(!leadingBreaks.empty() && leadingBreaks[0] == '\n') { + if(Exp::Break.Matches(leadingBreaks)) { // fold line break? if(trailingBreaks.empty()) scalar += ' '; - else { + else scalar += trailingBreaks; - trailingBreaks = ""; - } } else { scalar += leadingBreaks + trailingBreaks; - leadingBreaks = ""; - trailingBreaks = ""; } + + leadingBlanks = false; + leadingBreaks = ""; + trailingBreaks = ""; } else if(!whitespace.empty()) { scalar += whitespace; whitespace = ""; @@ -260,7 +265,8 @@ namespace YAML // now eat blanks while(INPUT && Exp::BlankOrBreak.Matches(INPUT)) { if(Exp::Blank.Matches(INPUT)) { - if(leadingBlanks && m_column <= m_indents.top()) + // can't use tabs as indentation! only spaces! + if(INPUT.peek() == '\t' && leadingBlanks && m_column <= m_indents.top()) throw IllegalTabInScalar(); // maybe store this character @@ -269,13 +275,17 @@ namespace YAML else Eat(1); } else { + // we know it's a line break; see how many characters to read + int n = Exp::Break.Match(INPUT); + std::string line = GetChar(n); + // where to store this character? if(!leadingBlanks) { leadingBlanks = true; whitespace = ""; - leadingBreaks += GetChar(); + leadingBreaks += line; } else - trailingBreaks += GetChar(); + trailingBreaks += line; } } @@ -285,10 +295,16 @@ namespace YAML } // now modify our token - pToken->SetValue(scalar); + pToken->value = scalar; if(leadingBlanks) m_simpleKeyAllowed = true; return pToken; } + + // QuotedScalarToken + template <> QuotedScalarToken *Scanner::ScanToken(QuotedScalarToken *pToken) + { + return pToken; + } } diff --git a/test.yaml b/test.yaml index d3ad2c7..64d38a7 100644 --- a/test.yaml +++ b/test.yaml @@ -1,5 +1,10 @@ --- -- milk +- green + eggs, + and + ham! - eggs # this is really important! -- cheese and bread +- - cheddar cheese + - american cheese +- bread ... \ No newline at end of file diff --git a/token.h b/token.h index ece11d8..acaebb7 100644 --- a/token.h +++ b/token.h @@ -1,32 +1,40 @@ #pragma once +#include + namespace YAML { - class Token { public: virtual ~Token() {} }; + struct Token { + virtual ~Token() {} + virtual void Write(std::ostream& out) const {} - class StreamStartToken: public Token {}; - class StreamEndToken: public Token {}; - class DocumentStartToken: public Token {}; - class DocumentEndToken: public Token {}; - - class BlockSeqStartToken: public Token {}; - class BlockMapStartToken: public Token {}; - class BlockEndToken: public Token {}; - class BlockEntryToken: public Token {}; - - class FlowSeqStartToken: public Token {}; - class FlowMapStartToken: public Token {}; - class FlowSeqEndToken: public Token {}; - class FlowMapEndToken: public Token {}; - class FlowEntryToken: public Token {}; - - class KeyToken: public Token {}; - class ValueToken: public Token {}; - - class PlainScalarToken: public Token { - public: - void SetValue(const std::string& value) { m_value = value; } - protected: - std::string m_value; + friend std::ostream& operator << (std::ostream& out, const Token& token) { token.Write(out); return out; } }; + + struct StreamStartToken: public Token {}; + struct StreamEndToken: public Token {}; + struct DocumentStartToken: public Token {}; + struct DocumentEndToken: public Token {}; + + struct BlockSeqStartToken: public Token {}; + struct BlockMapStartToken: public Token {}; + struct BlockEndToken: public Token {}; + struct BlockEntryToken: public Token {}; + + struct FlowSeqStartToken: public Token {}; + struct FlowMapStartToken: public Token {}; + struct FlowSeqEndToken: public Token {}; + struct FlowMapEndToken: public Token {}; + struct FlowEntryToken: public Token {}; + + struct KeyToken: public Token {}; + struct ValueToken: public Token {}; + + struct ScalarToken: public Token { + std::string value; + virtual void Write(std::ostream& out) const { out << value; } + }; + + struct PlainScalarToken: public ScalarToken {}; + struct QuotedScalarToken: public ScalarToken {}; } From fb9176a0543e5bb704356e5469cb0a9ac8c9e03a Mon Sep 17 00:00:00 2001 From: beder Date: Fri, 27 Jun 2008 23:11:46 +0000 Subject: [PATCH 014/295] Added quoted scalars (with escaping). Refactored some common whitespace-parsing code in scanning both scalars. Implemented the flow collection tokens. --- exceptions.h | 17 +++++ exp.cpp | 106 ++++++++++++++++++++++++++ exp.h | 14 +++- regex.cpp | 2 +- scanner.cpp | 16 ++++ scanner.h | 12 +++ scantoken.cpp | 180 ++++++++++++++++++++++++++++++++++----------- test.yaml | 10 +-- yaml-reader.vcproj | 4 + 9 files changed, 307 insertions(+), 54 deletions(-) create mode 100644 exp.cpp diff --git a/exceptions.h b/exceptions.h index 2b4e689..8af9dbd 100644 --- a/exceptions.h +++ b/exceptions.h @@ -12,4 +12,21 @@ namespace YAML class IllegalMapValue: public Exception {}; class IllegalScalar: public Exception {}; class IllegalTabInScalar: public Exception {}; + class DocIndicatorInQuote: public Exception {}; + class EOFInQuote: public Exception {}; + class UnknownEscapeSequence: public Exception { + public: + UnknownEscapeSequence(char ch_): ch(ch_) {} + char ch; + }; + class NonHexNumber: public Exception { + public: + NonHexNumber(char ch_): ch(ch_) {} + char ch; + }; + class InvalidUnicode: public Exception { + public: + InvalidUnicode(unsigned value_): value(value_) {} + unsigned value; + }; } diff --git a/exp.cpp b/exp.cpp new file mode 100644 index 0000000..21b0066 --- /dev/null +++ b/exp.cpp @@ -0,0 +1,106 @@ +#include "exp.h" +#include "exceptions.h" + +namespace YAML +{ + namespace Exp + { + unsigned ParseHex(std::string str) + { + unsigned value = 0; + for(unsigned i=0;i= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) + throw InvalidUnicode(value); + + // now break it up into chars + if(value <= 0x7F) + return Str(value); + else if(value <= 0x7FF) + return Str(0xC0 + (value >> 6)) + Str(0x80 + (value & 0x3F)); + else if(value <= 0xFFFF) + return Str(0xE0 + (value >> 12)) + Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F)); + else + return Str(0xF0 + (value >> 18)) + Str(0x80 + ((value >> 12) & 0x3F)) + + Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F)); + } + + // Escape + // . Escapes the sequence starting 'in' (it must begin with a '\') + // and returns the result. + // . Fills 'length' with how many characters we ate. + // . Throws if it's an unknown escape character. + std::string Escape(std::istream& in, int& length) + { + // slash + character + length = 2; + + // eat slash + in.get(); + + // switch on escape character + char ch = in.get(); + switch(ch) { + case '0': return "\0"; + case 'a': return "\x07"; + case 'b': return "\x08"; + case 't': + case '\t': return "\x09"; + case 'n': return "\x0A"; + case 'v': return "\x0B"; + case 'f': return "\x0C"; + case 'r': return "\x0D"; + case 'e': return "\x1B"; + case ' ': return "\x20"; + case '\"': return "\""; + case '\'': return "\'"; + case '\\': return "\\"; + case 'N': return "\xC2\x85"; // NEL (#x85) + case '_': return "\xC2\xA0"; // #xA0 + case 'L': return "\xE2\x80\xA8"; // LS (#x2028) + case 'P': return "\xE2\x80\xA9"; // PS (#x2029) + case 'x': return Escape(in, length, 2); + case 'u': return Escape(in, length, 4); + case 'U': return Escape(in, length, 8); + } + + throw UnknownEscapeSequence(ch); + } + } +} diff --git a/exp.h b/exp.h index bc2c59b..3ad948f 100644 --- a/exp.h +++ b/exp.h @@ -1,6 +1,8 @@ #pragma once #include "regex.h" +#include +#include namespace YAML { @@ -13,6 +15,8 @@ namespace YAML const RegEx Blank = RegEx(' ') || RegEx('\t'); const RegEx Break = RegEx('\n'); const RegEx BlankOrBreak = Blank || Break; + const RegEx Digit = RegEx('0', '9'); + const RegEx Hex = Digit || RegEx('A', 'F') || RegEx('a', 'f'); // actual tags @@ -30,11 +34,17 @@ namespace YAML // . Can never start with any of , [ ] { } # & * ! | > \' \" % @ ` // . In the block context - ? : must be not be followed with a space. // . In the flow context ? : are illegal and - must not be followed with a space. - const RegEx PlainScalar = !(BlankOrBreak || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:") + Blank)), + const RegEx PlainScalar = !(BlankOrBreak || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:", REGEX_OR) + Blank)), PlainScalarInFlow = !(BlankOrBreak || RegEx("?:,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx('-') + Blank)); const RegEx IllegalColonInScalar = RegEx(':') + !BlankOrBreak; const RegEx EndScalar = RegEx(':') + BlankOrBreak, - EndScalarInFlow = (RegEx(':') + BlankOrBreak) || RegEx(",:?[]{}"); + EndScalarInFlow = (RegEx(':') + BlankOrBreak) || RegEx(",:?[]{}", REGEX_OR); + + const RegEx EscSingleQuote = RegEx("\'\'"); + const RegEx EscBreak = RegEx('\\') + Break; + + // and some functions + std::string Escape(std::istream& in, int& length); } namespace Keys diff --git a/regex.cpp b/regex.cpp index f7830b7..342c0bd 100644 --- a/regex.cpp +++ b/regex.cpp @@ -35,7 +35,7 @@ namespace YAML RegEx::RegEx(const std::string& str, REGEX_OP op): m_op(op), m_pOp(0) { for(unsigned i=0;i 0) { + m_flowLevel--; + // TODO: Pop simple key + } + } + // temporary function for testing void Scanner::Scan() { diff --git a/scanner.h b/scanner.h index 8db99be..df89944 100644 --- a/scanner.h +++ b/scanner.h @@ -20,6 +20,8 @@ namespace YAML void ScanToNextToken(); void PushIndentTo(int column, bool sequence); void PopIndentTo(int column); + void IncreaseFlowLevel(); + void DecreaseFlowLevel(); void Scan(); @@ -37,6 +39,16 @@ namespace YAML bool IsValue(); bool IsPlainScalar(); + struct WhitespaceInfo { + WhitespaceInfo(); + void AddBlank(char ch); + void AddBreak(const std::string& line); + std::string Join(); + + bool leadingBlanks; + std::string whitespace, leadingBreaks, trailingBreaks; + }; + template void ScanAndEnqueue(T *pToken); template T *ScanToken(T *pToken); diff --git a/scantoken.cpp b/scantoken.cpp index 0b24d9a..48141fd 100644 --- a/scantoken.cpp +++ b/scantoken.cpp @@ -64,8 +64,8 @@ namespace YAML template <> FlowSeqStartToken *Scanner::ScanToken(FlowSeqStartToken *pToken) { // TODO: "save simple key" - // TODO: increase flow level + IncreaseFlowLevel(); m_simpleKeyAllowed = true; // eat @@ -77,8 +77,8 @@ namespace YAML template <> FlowMapStartToken *Scanner::ScanToken(FlowMapStartToken *pToken) { // TODO: "save simple key" - // TODO: increase flow level + IncreaseFlowLevel(); m_simpleKeyAllowed = true; // eat @@ -90,8 +90,8 @@ namespace YAML template <> FlowSeqEndToken *Scanner::ScanToken(FlowSeqEndToken *pToken) { // TODO: "remove simple key" - // TODO: decrease flow level + DecreaseFlowLevel(); m_simpleKeyAllowed = false; // eat @@ -103,8 +103,8 @@ namespace YAML template <> FlowMapEndToken *Scanner::ScanToken(FlowMapEndToken *pToken) { // TODO: "remove simple key" - // TODO: decrease flow level + DecreaseFlowLevel(); m_simpleKeyAllowed = false; // eat @@ -210,8 +210,8 @@ namespace YAML m_simpleKeyAllowed = false; // now eat and store the scalar - std::string scalar, whitespace, leadingBreaks, trailingBreaks; - bool leadingBlanks = false; + std::string scalar; + WhitespaceInfo info; while(INPUT) { // doc start/end tokens @@ -234,26 +234,6 @@ namespace YAML if(m_flowLevel == 0 && Exp::EndScalar.Matches(INPUT)) break; - // join whitespace - if(leadingBlanks) { - if(Exp::Break.Matches(leadingBreaks)) { - // fold line break? - if(trailingBreaks.empty()) - scalar += ' '; - else - scalar += trailingBreaks; - } else { - scalar += leadingBreaks + trailingBreaks; - } - - leadingBlanks = false; - leadingBreaks = ""; - trailingBreaks = ""; - } else if(!whitespace.empty()) { - scalar += whitespace; - whitespace = ""; - } - // finally, read the character! scalar += GetChar(); } @@ -266,37 +246,29 @@ namespace YAML while(INPUT && Exp::BlankOrBreak.Matches(INPUT)) { if(Exp::Blank.Matches(INPUT)) { // can't use tabs as indentation! only spaces! - if(INPUT.peek() == '\t' && leadingBlanks && m_column <= m_indents.top()) + if(INPUT.peek() == '\t' && info.leadingBlanks && m_column <= m_indents.top()) throw IllegalTabInScalar(); - // maybe store this character - if(!leadingBlanks) - whitespace += GetChar(); - else - Eat(1); - } else { + info.AddBlank(GetChar()); + } else { // we know it's a line break; see how many characters to read int n = Exp::Break.Match(INPUT); std::string line = GetChar(n); - - // where to store this character? - if(!leadingBlanks) { - leadingBlanks = true; - whitespace = ""; - leadingBreaks += line; - } else - trailingBreaks += line; + info.AddBreak(line); } } - // and finally break if we're below the indentation level + // break if we're below the indentation level if(m_flowLevel == 0 && m_column <= m_indents.top()) break; + + // finally join whitespace + scalar += info.Join(); } // now modify our token pToken->value = scalar; - if(leadingBlanks) + if(info.leadingBlanks) m_simpleKeyAllowed = true; return pToken; @@ -305,6 +277,128 @@ namespace YAML // QuotedScalarToken template <> QuotedScalarToken *Scanner::ScanToken(QuotedScalarToken *pToken) { + // TODO: "save simple key" + + m_simpleKeyAllowed = false; + + // eat single or double quote + char quote = GetChar(); + bool single = (quote == '\''); + + // now eat and store the scalar + std::string scalar; + WhitespaceInfo info; + + while(INPUT) { + if(IsDocumentStart() || IsDocumentEnd()) + throw DocIndicatorInQuote(); + + if(INPUT.peek() == EOF) + throw EOFInQuote(); + + // first eat non-blanks + while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) { + // escaped single quote? + if(single && Exp::EscSingleQuote.Matches(INPUT)) { + int n = Exp::EscSingleQuote.Match(INPUT); + scalar += GetChar(n); + continue; + } + + // is the quote ending? + if(INPUT.peek() == (single ? '\'' : '\"')) + break; + + // escaped newline? + if(Exp::EscBreak.Matches(INPUT)) + break; + + // other escape sequence + if(INPUT.peek() == '\\') { + int length = 0; + scalar += Exp::Escape(INPUT, length); + m_column += length; + continue; + } + + // and finally, just add the damn character + scalar += GetChar(); + } + + // is the quote ending? + if(INPUT.peek() == (single ? '\'' : '\"')) { + // eat and go + GetChar(); + break; + } + + // now we eat blanks + while(Exp::BlankOrBreak.Matches(INPUT)) { + if(Exp::Blank.Matches(INPUT)) { + info.AddBlank(GetChar()); + } else { + // we know it's a line break; see how many characters to read + int n = Exp::Break.Match(INPUT); + std::string line = GetChar(n); + info.AddBreak(line); + } + } + + // and finally join the whitespace + scalar += info.Join(); + } + + pToken->value = scalar; return pToken; } + + ////////////////////////////////////////////////////////// + // WhitespaceInfo stuff + + Scanner::WhitespaceInfo::WhitespaceInfo(): leadingBlanks(false) + { + } + + void Scanner::WhitespaceInfo::AddBlank(char ch) + { + if(!leadingBlanks) + whitespace += ch; + } + + void Scanner::WhitespaceInfo::AddBreak(const std::string& line) + { + // where to store this character? + if(!leadingBlanks) { + leadingBlanks = true; + whitespace = ""; + leadingBreaks += line; + } else + trailingBreaks += line; + } + + std::string Scanner::WhitespaceInfo::Join() + { + std::string ret; + + if(leadingBlanks) { + if(Exp::Break.Matches(leadingBreaks)) { + // fold line break? + if(trailingBreaks.empty()) + ret = " "; + else + ret = trailingBreaks; + } else { + ret = leadingBreaks + trailingBreaks; + } + + leadingBlanks = false; + leadingBreaks = ""; + trailingBreaks = ""; + } else if(!whitespace.empty()) { + ret = whitespace; + whitespace = ""; + } + + return ret; + } } diff --git a/test.yaml b/test.yaml index 64d38a7..5e865dd 100644 --- a/test.yaml +++ b/test.yaml @@ -1,10 +1,4 @@ --- -- green - eggs, - and - ham! -- eggs # this is really important! -- - cheddar cheese - - american cheese -- bread +- milk and eggs +- [cheddar, american, swiss] ... \ No newline at end of file diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index 39f42a4..bcb10e8 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -169,6 +169,10 @@ RelativePath=".\document.cpp" > + + From 70afd130ada2f5fc43ea7c68657775aa7f302ea9 Mon Sep 17 00:00:00 2001 From: beder Date: Sat, 28 Jun 2008 06:36:59 +0000 Subject: [PATCH 015/295] Added simple keys. There's a bug (and question): should we test simple keys' validity BEFORE stuff or AFTER stuff? --- exceptions.h | 2 + exp.cpp | 66 +++++++++++++++--------------- scanner.cpp | 41 ++++++++++++++----- scanner.h | 21 +++++++++- scantoken.cpp | 64 +++++++++++++++-------------- simplekey.cpp | 100 +++++++++++++++++++++++++++++++++++++++++++++ test.yaml | 100 +++++++++++++++++++++++++++++++++++++++++++-- token.h | 2 + yaml-reader.vcproj | 4 ++ 9 files changed, 321 insertions(+), 79 deletions(-) create mode 100644 simplekey.cpp diff --git a/exceptions.h b/exceptions.h index 8af9dbd..cd39abc 100644 --- a/exceptions.h +++ b/exceptions.h @@ -14,6 +14,8 @@ namespace YAML class IllegalTabInScalar: public Exception {}; class DocIndicatorInQuote: public Exception {}; class EOFInQuote: public Exception {}; + class RequiredSimpleKeyNotFound: public Exception {}; + class UnknownEscapeSequence: public Exception { public: UnknownEscapeSequence(char ch_): ch(ch_) {} diff --git a/exp.cpp b/exp.cpp index 21b0066..07e4d2b 100644 --- a/exp.cpp +++ b/exp.cpp @@ -46,18 +46,18 @@ namespace YAML unsigned value = ParseHex(str); // legal unicode? - if((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) - throw InvalidUnicode(value); - - // now break it up into chars - if(value <= 0x7F) - return Str(value); - else if(value <= 0x7FF) - return Str(0xC0 + (value >> 6)) + Str(0x80 + (value & 0x3F)); - else if(value <= 0xFFFF) - return Str(0xE0 + (value >> 12)) + Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F)); - else - return Str(0xF0 + (value >> 18)) + Str(0x80 + ((value >> 12) & 0x3F)) + + if((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) + throw InvalidUnicode(value); + + // now break it up into chars + if(value <= 0x7F) + return Str(value); + else if(value <= 0x7FF) + return Str(0xC0 + (value >> 6)) + Str(0x80 + (value & 0x3F)); + else if(value <= 0xFFFF) + return Str(0xE0 + (value >> 12)) + Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F)); + else + return Str(0xF0 + (value >> 18)) + Str(0x80 + ((value >> 12) & 0x3F)) + Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F)); } @@ -76,27 +76,27 @@ namespace YAML // switch on escape character char ch = in.get(); - switch(ch) { - case '0': return "\0"; - case 'a': return "\x07"; - case 'b': return "\x08"; - case 't': - case '\t': return "\x09"; - case 'n': return "\x0A"; - case 'v': return "\x0B"; - case 'f': return "\x0C"; - case 'r': return "\x0D"; - case 'e': return "\x1B"; - case ' ': return "\x20"; - case '\"': return "\""; - case '\'': return "\'"; - case '\\': return "\\"; - case 'N': return "\xC2\x85"; // NEL (#x85) - case '_': return "\xC2\xA0"; // #xA0 - case 'L': return "\xE2\x80\xA8"; // LS (#x2028) - case 'P': return "\xE2\x80\xA9"; // PS (#x2029) - case 'x': return Escape(in, length, 2); - case 'u': return Escape(in, length, 4); + switch(ch) { + case '0': return "\0"; + case 'a': return "\x07"; + case 'b': return "\x08"; + case 't': + case '\t': return "\x09"; + case 'n': return "\x0A"; + case 'v': return "\x0B"; + case 'f': return "\x0C"; + case 'r': return "\x0D"; + case 'e': return "\x1B"; + case ' ': return "\x20"; + case '\"': return "\""; + case '\'': return "\'"; + case '\\': return "\\"; + case 'N': return "\xC2\x85"; // NEL (#x85) + case '_': return "\xC2\xA0"; // #xA0 + case 'L': return "\xE2\x80\xA8"; // LS (#x2028) + case 'P': return "\xE2\x80\xA9"; // PS (#x2029) + case 'x': return Escape(in, length, 2); + case 'u': return Escape(in, length, 4); case 'U': return Escape(in, length, 8); } diff --git a/scanner.cpp b/scanner.cpp index a7f5c44..c3477b7 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -7,7 +7,8 @@ namespace YAML { Scanner::Scanner(std::istream& in) - : INPUT(in), m_startedStream(false), m_endedStream(false), m_simpleKeyAllowed(false), m_flowLevel(0), m_column(0) + : INPUT(in), m_startedStream(false), m_endedStream(false), m_simpleKeyAllowed(false), m_flowLevel(0), + m_line(0), m_column(0) { } @@ -32,8 +33,10 @@ namespace YAML { m_column++; char ch = INPUT.get(); - if(ch == '\n') + if(ch == '\n') { m_column = 0; + m_line++; + } return ch; } @@ -51,12 +54,8 @@ namespace YAML // . Eats 'n' characters and updates our position. void Scanner::Eat(int n) { - for(int i=0;i temp; + while(!m_tokens.empty()) { + Token *pToken = m_tokens.front(); + m_tokens.pop(); + if(pToken->isPossible) + temp.push(pToken); + } + + m_tokens = temp; } /////////////////////////////////////////////////////////////////////// @@ -243,6 +253,9 @@ namespace YAML // otherwise, let's eat the line break and keep going EatLineBreak(); + // oh yeah, and let's get rid of that simple key + ValidateSimpleKey(); + // new line - we may be able to accept a simple key now if(m_flowLevel == 0) m_simpleKeyAllowed = true; @@ -252,15 +265,16 @@ namespace YAML // PushIndentTo // . Pushes an indentation onto the stack, and enqueues the // proper token (sequence start or mapping start). - void Scanner::PushIndentTo(int column, bool sequence) + // . Returns the token it generates (if any). + Token *Scanner::PushIndentTo(int column, bool sequence) { // are we in flow? if(m_flowLevel > 0) - return; + return 0; // is this actually an indentation? if(column <= m_indents.top()) - return; + return 0; // now push m_indents.push(column); @@ -268,6 +282,8 @@ namespace YAML m_tokens.push(new BlockSeqStartToken); else m_tokens.push(new BlockMapStartToken); + + return m_tokens.front(); } // PopIndentTo @@ -312,6 +328,9 @@ namespace YAML while(!m_tokens.empty()) { Token *pToken = m_tokens.front(); + if(!pToken->isValid) // gotta wait on the invalid tokens - they might become valid! + break; + m_tokens.pop(); std::cout << typeid(*pToken).name() << ": " << *pToken << std::endl; delete pToken; diff --git a/scanner.h b/scanner.h index df89944..36362ac 100644 --- a/scanner.h +++ b/scanner.h @@ -18,11 +18,15 @@ namespace YAML void ScanNextToken(); void ScanToNextToken(); - void PushIndentTo(int column, bool sequence); + Token *PushIndentTo(int column, bool sequence); void PopIndentTo(int column); void IncreaseFlowLevel(); void DecreaseFlowLevel(); + void InsertSimpleKey(); + bool ValidateSimpleKey(); + void ValidateAllSimpleKeys(); + void Scan(); private: @@ -41,6 +45,7 @@ namespace YAML struct WhitespaceInfo { WhitespaceInfo(); + void AddBlank(char ch); void AddBreak(const std::string& line); std::string Join(); @@ -49,13 +54,24 @@ namespace YAML std::string whitespace, leadingBreaks, trailingBreaks; }; + struct SimpleKey { + SimpleKey(int pos_, int line_, int column_); + + void Validate(); + void Invalidate(); + + int pos, line, column; + bool required; + Token *pMapStart, *pKey; + }; + template void ScanAndEnqueue(T *pToken); template T *ScanToken(T *pToken); private: // the stream std::istream& INPUT; - int m_column; + int m_line, m_column; // the output (tokens) std::queue m_tokens; @@ -65,6 +81,7 @@ namespace YAML bool m_startedStream, m_endedStream; bool m_simpleKeyAllowed; int m_flowLevel; // number of unclosed '[' and '{' indicators + std::stack m_simpleKeys; std::stack m_indents; }; } diff --git a/scantoken.cpp b/scantoken.cpp index 48141fd..ed69bd8 100644 --- a/scantoken.cpp +++ b/scantoken.cpp @@ -26,7 +26,7 @@ namespace YAML m_column = 0; PopIndentTo(-1); - // TODO: "reset simple keys" + ValidateAllSimpleKeys(); m_simpleKeyAllowed = false; m_endedStream = true; @@ -38,8 +38,7 @@ namespace YAML template <> DocumentStartToken *Scanner::ScanToken(DocumentStartToken *pToken) { PopIndentTo(m_column); - // TODO: "reset simple keys" - + ValidateAllSimpleKeys(); m_simpleKeyAllowed = false; // eat @@ -51,8 +50,7 @@ namespace YAML template <> DocumentEndToken *Scanner::ScanToken(DocumentEndToken *pToken) { PopIndentTo(-1); - // TODO: "reset simple keys" - + ValidateAllSimpleKeys(); m_simpleKeyAllowed = false; // eat @@ -63,8 +61,8 @@ namespace YAML // FlowSeqStartToken template <> FlowSeqStartToken *Scanner::ScanToken(FlowSeqStartToken *pToken) { - // TODO: "save simple key" - + // flow sequences can be simple keys + InsertSimpleKey(); IncreaseFlowLevel(); m_simpleKeyAllowed = true; @@ -76,8 +74,8 @@ namespace YAML // FlowMapStartToken template <> FlowMapStartToken *Scanner::ScanToken(FlowMapStartToken *pToken) { - // TODO: "save simple key" - + // flow maps can be simple keys + InsertSimpleKey(); IncreaseFlowLevel(); m_simpleKeyAllowed = true; @@ -89,8 +87,7 @@ namespace YAML // FlowSeqEndToken template <> FlowSeqEndToken *Scanner::ScanToken(FlowSeqEndToken *pToken) { - // TODO: "remove simple key" - +// ValidateSimpleKey(); DecreaseFlowLevel(); m_simpleKeyAllowed = false; @@ -102,8 +99,7 @@ namespace YAML // FlowMapEndToken template <> FlowMapEndToken *Scanner::ScanToken(FlowMapEndToken *pToken) { - // TODO: "remove simple key" - + ValidateSimpleKey(); DecreaseFlowLevel(); m_simpleKeyAllowed = false; @@ -115,8 +111,7 @@ namespace YAML // FlowEntryToken template <> FlowEntryToken *Scanner::ScanToken(FlowEntryToken *pToken) { - // TODO: "remove simple key" - + ValidateSimpleKey(); m_simpleKeyAllowed = true; // eat @@ -127,6 +122,8 @@ namespace YAML // BlockEntryToken template <> BlockEntryToken *Scanner::ScanToken(BlockEntryToken *pToken) { + ValidateSimpleKey(); + // we better be in the block context! if(m_flowLevel == 0) { // can we put it here? @@ -138,8 +135,6 @@ namespace YAML // TODO: throw? } - // TODO: "remove simple key" - m_simpleKeyAllowed = true; // eat @@ -174,10 +169,13 @@ namespace YAML // ValueToken template <> ValueToken *Scanner::ScanToken(ValueToken *pToken) { - // TODO: Is it a simple key? - if(false) { + // does this follow a simple key? + bool isValidKey = ValidateSimpleKey(); + + if(isValidKey) { + // can't follow a simple key with another simple key (dunno why, though - it seems fine) + m_simpleKeyAllowed = false; } else { - // If not, ... // are we in block context? if(m_flowLevel == 0) { if(!m_simpleKeyAllowed) @@ -185,13 +183,13 @@ namespace YAML PushIndentTo(m_column, false); } - } - // can only put a simple key here if we're in block context - if(m_flowLevel == 0) - m_simpleKeyAllowed = true; - else - m_simpleKeyAllowed = false; + // can only put a simple key here if we're in block context + if(m_flowLevel == 0) + m_simpleKeyAllowed = true; + else + m_simpleKeyAllowed = false; + } // eat Eat(1); @@ -205,8 +203,8 @@ namespace YAML // and in-line whitespace (which is kept) separately. template <> PlainScalarToken *Scanner::ScanToken(PlainScalarToken *pToken) { - // TODO: "save simple key" - + // insert a potential simple key + InsertSimpleKey(); m_simpleKeyAllowed = false; // now eat and store the scalar @@ -255,6 +253,9 @@ namespace YAML int n = Exp::Break.Match(INPUT); std::string line = GetChar(n); info.AddBreak(line); + + // and we can't continue a simple key to the next line + ValidateSimpleKey(); } } @@ -277,8 +278,8 @@ namespace YAML // QuotedScalarToken template <> QuotedScalarToken *Scanner::ScanToken(QuotedScalarToken *pToken) { - // TODO: "save simple key" - + // insert a potential simple key + InsertSimpleKey(); m_simpleKeyAllowed = false; // eat single or double quote @@ -341,6 +342,9 @@ namespace YAML int n = Exp::Break.Match(INPUT); std::string line = GetChar(n); info.AddBreak(line); + + // and we can't continue a simple key to the next line + ValidateSimpleKey(); } } diff --git a/simplekey.cpp b/simplekey.cpp new file mode 100644 index 0000000..990d24d --- /dev/null +++ b/simplekey.cpp @@ -0,0 +1,100 @@ +#include "scanner.h" +#include "token.h" +#include "exceptions.h" +#include "exp.h" + +namespace YAML +{ + Scanner::SimpleKey::SimpleKey(int pos_, int line_, int column_) + : pos(pos_), line(line_), column(column_), required(false), pMapStart(0), pKey(0) + { + } + + void Scanner::SimpleKey::Validate() + { + if(pMapStart) + pMapStart->isValid = true; + if(pKey) + pKey->isValid = true; + } + + void Scanner::SimpleKey::Invalidate() + { + if(required) + throw RequiredSimpleKeyNotFound(); + + if(pMapStart) + pMapStart->isPossible = false; + if(pKey) + pKey->isPossible = false; + } + + // InsertSimpleKey + // . Adds a potential simple key to the queue, + // and saves it on a stack. + void Scanner::InsertSimpleKey() + { + SimpleKey key(INPUT.tellg(), m_line, m_column); + + // first add a map start, if necessary + key.pMapStart = PushIndentTo(m_column, false); + if(key.pMapStart) + key.pMapStart->isValid = false; +// else +// key.required = true; // TODO: is this correct? + + // then add the (now invalid) key + key.pKey = new KeyToken; + key.pKey->isValid = false; + + m_tokens.push(key.pKey); + + m_simpleKeys.push(key); + } + + // ValidateSimpleKey + // . Determines whether the latest simple key to be added is valid, + // and if so, makes it valid. + bool Scanner::ValidateSimpleKey() + { + if(m_simpleKeys.empty()) + return false; + + // grab top key + SimpleKey key = m_simpleKeys.top(); + m_simpleKeys.pop(); + + bool isValid = true; + + // needs to be followed immediately by a value + if(m_flowLevel > 0 && !Exp::ValueInFlow.Matches(INPUT)) + isValid = false; + if(m_flowLevel == 0 && !Exp::Value.Matches(INPUT)) + isValid = false; + + // also needs to be less than 1024 characters and inline + if(m_line != key.line || (int) INPUT.tellg() - key.pos > 1024) + isValid = false; + + // invalidate key + if(isValid) + key.Validate(); + else + key.Invalidate(); + + // In block style, remember that we've pushed an indent for this potential simple key (if it was starting). + // If it was invalid, then we need to pop it off. + // Note: we're guaranteed to be popping the right one (i.e., there couldn't have been anything in + // between) since keys have to be inline, and will be invalidated immediately on a newline. + if(!isValid && m_flowLevel == 0) + m_indents.pop(); + + return isValid; + } + + void Scanner::ValidateAllSimpleKeys() + { + while(!m_simpleKeys.empty()) + ValidateSimpleKey(); + } +} diff --git a/test.yaml b/test.yaml index 5e865dd..f58841b 100644 --- a/test.yaml +++ b/test.yaml @@ -1,4 +1,98 @@ --- -- milk and eggs -- [cheddar, american, swiss] -... \ No newline at end of file +model: + file: data/models/compound.model + textures: data/materials/compound +rooms: + - name: "Room #1" + pos: [0, 0, 0] + size: [1000, 1000, 500] + height: 500 + stairtype: none + display: [] + pathfinding: + tilesize: 50 + size: [24, 24] + map: + ----------------------- + -+++++++++++++++++++++- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+--------------------- + -+--------------------- + -+--------------------- + -+--------------------- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+++++++++++++++++++++- + ----------------------- + - name: Doorway + pos: [1000, 400, 0] + size: [50, 200, 500] + height: 500 + stairtype: none + display: [] + pathfinding: + tilesize: 50 + size: [5, 9] + map: + ----- + -+++- + ----- + ----- + ----- + ----- + ----- + -+++- + ----- + - name: "Room #2" + pos: [1050, 0, 0] + size: [1000, 1000, 500] + height: 500 + stairtype: none + display: [] + pathfinding: + tilesize: 50 + size: [24, 24] + map: + ----------------------- + -+++++++++++++++++++++- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + ---------------------+- + ---------------------+- + ---------------------+- + ---------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+++++++++++++++++++++- + ----------------------- +exits: + - room1: "Room #1" + room2: "Room #2" + dir: e + pos: [400, 600] +... diff --git a/token.h b/token.h index acaebb7..fec77d2 100644 --- a/token.h +++ b/token.h @@ -5,10 +5,12 @@ namespace YAML { struct Token { + Token(): isValid(true), isPossible(true) {} virtual ~Token() {} virtual void Write(std::ostream& out) const {} friend std::ostream& operator << (std::ostream& out, const Token& token) { token.Write(out); return out; } + bool isValid, isPossible; }; struct StreamStartToken: public Token {}; diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index bcb10e8..b0c6da3 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -209,6 +209,10 @@ RelativePath=".\sequence.cpp" > + + Date: Sat, 28 Jun 2008 16:46:37 +0000 Subject: [PATCH 016/295] Moved the simple key validation to before each token scan (plus at newlines of scalars). --- scanner.cpp | 68 ++++++++++++++++++++++++++++++++++----------------- scanner.h | 7 ++++-- scantoken.cpp | 10 ++++---- simplekey.cpp | 15 +++++++++--- 4 files changed, 66 insertions(+), 34 deletions(-) diff --git a/scanner.cpp b/scanner.cpp index c3477b7..f6c844b 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -146,17 +146,6 @@ namespace YAML m_limboTokens.insert(pToken); m_tokens.push(ScanToken(pToken)); m_limboTokens.erase(pToken); - - // then remove impossible tokens - std::queue temp; - while(!m_tokens.empty()) { - Token *pToken = m_tokens.front(); - m_tokens.pop(); - if(pToken->isPossible) - temp.push(pToken); - } - - m_tokens = temp; } /////////////////////////////////////////////////////////////////////// @@ -171,7 +160,7 @@ namespace YAML return ScanAndEnqueue(new StreamStartToken); ScanToNextToken(); - // TODO: remove "obsolete potential simple keys" + ValidateSimpleKey(); PopIndentTo(m_column); if(INPUT.peek() == EOF) @@ -318,23 +307,56 @@ namespace YAML } } + // GetNextToken + // . Returns the next token on the queue, and scans if only we need to. + Token *Scanner::GetNextToken() + { + while(1) { + Token *pToken = 0; + + // is there a token in the queue? + if(!m_tokens.empty()) + pToken = m_tokens.front(); + + // ... that's possible + // (here's where we clean up the impossible tokens) + if(pToken && !pToken->isPossible) { + m_tokens.pop(); + delete pToken; + continue; + } + + // and valid + if(pToken && !pToken->isValid) + pToken = 0; + + // then that's what we want + if(pToken) { + m_tokens.pop(); + return pToken; + } + + // no token? maybe we've actually finished + if(m_endedStream) + break; + + // no? then scan... + ScanNextToken(); + } + + return 0; + } + // temporary function for testing void Scanner::Scan() { while(1) { - ScanNextToken(); - if(m_tokens.empty()) + Token *pToken = GetNextToken(); + if(!pToken) break; - while(!m_tokens.empty()) { - Token *pToken = m_tokens.front(); - if(!pToken->isValid) // gotta wait on the invalid tokens - they might become valid! - break; - - m_tokens.pop(); - std::cout << typeid(*pToken).name() << ": " << *pToken << std::endl; - delete pToken; - } + std::cout << typeid(*pToken).name() << ": " << *pToken << std::endl; + delete pToken; } } } diff --git a/scanner.h b/scanner.h index 36362ac..8d0033b 100644 --- a/scanner.h +++ b/scanner.h @@ -16,6 +16,8 @@ namespace YAML Scanner(std::istream& in); ~Scanner(); + Token *GetNextToken(); + void ScanNextToken(); void ScanToNextToken(); Token *PushIndentTo(int column, bool sequence); @@ -55,12 +57,12 @@ namespace YAML }; struct SimpleKey { - SimpleKey(int pos_, int line_, int column_); + SimpleKey(int pos_, int line_, int column_, int flowLevel_); void Validate(); void Invalidate(); - int pos, line, column; + int pos, line, column, flowLevel; bool required; Token *pMapStart, *pKey; }; @@ -81,6 +83,7 @@ namespace YAML bool m_startedStream, m_endedStream; bool m_simpleKeyAllowed; int m_flowLevel; // number of unclosed '[' and '{' indicators + bool m_isLastKeyValid; std::stack m_simpleKeys; std::stack m_indents; }; diff --git a/scantoken.cpp b/scantoken.cpp index ed69bd8..6b071c0 100644 --- a/scantoken.cpp +++ b/scantoken.cpp @@ -99,7 +99,7 @@ namespace YAML // FlowMapEndToken template <> FlowMapEndToken *Scanner::ScanToken(FlowMapEndToken *pToken) { - ValidateSimpleKey(); + //ValidateSimpleKey(); DecreaseFlowLevel(); m_simpleKeyAllowed = false; @@ -111,7 +111,7 @@ namespace YAML // FlowEntryToken template <> FlowEntryToken *Scanner::ScanToken(FlowEntryToken *pToken) { - ValidateSimpleKey(); + //ValidateSimpleKey(); m_simpleKeyAllowed = true; // eat @@ -122,7 +122,7 @@ namespace YAML // BlockEntryToken template <> BlockEntryToken *Scanner::ScanToken(BlockEntryToken *pToken) { - ValidateSimpleKey(); + //ValidateSimpleKey(); // we better be in the block context! if(m_flowLevel == 0) { @@ -170,9 +170,9 @@ namespace YAML template <> ValueToken *Scanner::ScanToken(ValueToken *pToken) { // does this follow a simple key? - bool isValidKey = ValidateSimpleKey(); +// bool isValidKey = ValidateSimpleKey(); - if(isValidKey) { + if(m_isLastKeyValid) { // can't follow a simple key with another simple key (dunno why, though - it seems fine) m_simpleKeyAllowed = false; } else { diff --git a/simplekey.cpp b/simplekey.cpp index 990d24d..cf90bd2 100644 --- a/simplekey.cpp +++ b/simplekey.cpp @@ -5,8 +5,8 @@ namespace YAML { - Scanner::SimpleKey::SimpleKey(int pos_, int line_, int column_) - : pos(pos_), line(line_), column(column_), required(false), pMapStart(0), pKey(0) + Scanner::SimpleKey::SimpleKey(int pos_, int line_, int column_, int flowLevel_) + : pos(pos_), line(line_), column(column_), flowLevel(flowLevel_), required(false), pMapStart(0), pKey(0) { } @@ -34,7 +34,7 @@ namespace YAML // and saves it on a stack. void Scanner::InsertSimpleKey() { - SimpleKey key(INPUT.tellg(), m_line, m_column); + SimpleKey key(INPUT.tellg(), m_line, m_column, m_flowLevel); // first add a map start, if necessary key.pMapStart = PushIndentTo(m_column, false); @@ -57,11 +57,17 @@ namespace YAML // and if so, makes it valid. bool Scanner::ValidateSimpleKey() { + m_isLastKeyValid = false; if(m_simpleKeys.empty()) - return false; + return m_isLastKeyValid; // grab top key SimpleKey key = m_simpleKeys.top(); + + // only validate if we're in the correct flow level + if(key.flowLevel != m_flowLevel) + return false; + m_simpleKeys.pop(); bool isValid = true; @@ -89,6 +95,7 @@ namespace YAML if(!isValid && m_flowLevel == 0) m_indents.pop(); + m_isLastKeyValid = isValid; return isValid; } From 1a96548fa5fbd5bcb9d6ea8eaf842ed4662eca97 Mon Sep 17 00:00:00 2001 From: beder Date: Sat, 28 Jun 2008 17:32:10 +0000 Subject: [PATCH 017/295] Fixed complex keys. --- scanner.cpp | 6 +-- scantoken.cpp | 6 ++- test.yaml | 102 ++------------------------------------------------ 3 files changed, 11 insertions(+), 103 deletions(-) diff --git a/scanner.cpp b/scanner.cpp index f6c844b..d785706 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -229,14 +229,14 @@ namespace YAML Eat(1); // then eat a comment - if(Exp::Comment.Matches(INPUT.peek())) { + if(Exp::Comment.Matches(INPUT)) { // eat until line break - while(INPUT && !Exp::Break.Matches(INPUT.peek())) + while(INPUT && !Exp::Break.Matches(INPUT)) Eat(1); } // if it's NOT a line break, then we're done! - if(!Exp::Break.Matches(INPUT.peek())) + if(!Exp::Break.Matches(INPUT)) break; // otherwise, let's eat the line break and keep going diff --git a/scantoken.cpp b/scantoken.cpp index 6b071c0..0cc741e 100644 --- a/scantoken.cpp +++ b/scantoken.cpp @@ -204,7 +204,8 @@ namespace YAML template <> PlainScalarToken *Scanner::ScanToken(PlainScalarToken *pToken) { // insert a potential simple key - InsertSimpleKey(); + if(m_simpleKeyAllowed) + InsertSimpleKey(); m_simpleKeyAllowed = false; // now eat and store the scalar @@ -279,7 +280,8 @@ namespace YAML template <> QuotedScalarToken *Scanner::ScanToken(QuotedScalarToken *pToken) { // insert a potential simple key - InsertSimpleKey(); + if(m_simpleKeyAllowed) + InsertSimpleKey(); m_simpleKeyAllowed = false; // eat single or double quote diff --git a/test.yaml b/test.yaml index f58841b..3cb65c2 100644 --- a/test.yaml +++ b/test.yaml @@ -1,98 +1,4 @@ ---- -model: - file: data/models/compound.model - textures: data/materials/compound -rooms: - - name: "Room #1" - pos: [0, 0, 0] - size: [1000, 1000, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [24, 24] - map: - ----------------------- - -+++++++++++++++++++++- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+--------------------- - -+--------------------- - -+--------------------- - -+--------------------- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+++++++++++++++++++++- - ----------------------- - - name: Doorway - pos: [1000, 400, 0] - size: [50, 200, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [5, 9] - map: - ----- - -+++- - ----- - ----- - ----- - ----- - ----- - -+++- - ----- - - name: "Room #2" - pos: [1050, 0, 0] - size: [1000, 1000, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [24, 24] - map: - ----------------------- - -+++++++++++++++++++++- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - ---------------------+- - ---------------------+- - ---------------------+- - ---------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+++++++++++++++++++++- - ----------------------- -exits: - - room1: "Room #1" - room2: "Room #2" - dir: e - pos: [400, 600] -... +{ + a simple key: a value, + ? a complex key: another value, +} \ No newline at end of file From 566916ba1924e4e11594d955d63f1161b527b8de Mon Sep 17 00:00:00 2001 From: beder Date: Sat, 28 Jun 2008 20:08:21 +0000 Subject: [PATCH 018/295] Added folded and literal scalars. --- exceptions.h | 2 + exp.h | 3 ++ scanner.cpp | 11 ++-- scanner.h | 7 ++- scantoken.cpp | 145 ++++++++++++++++++++++++++++++++++++++++++++++---- test.yaml | 7 ++- token.h | 1 + 7 files changed, 153 insertions(+), 23 deletions(-) diff --git a/exceptions.h b/exceptions.h index cd39abc..1e0867b 100644 --- a/exceptions.h +++ b/exceptions.h @@ -15,6 +15,8 @@ namespace YAML class DocIndicatorInQuote: public Exception {}; class EOFInQuote: public Exception {}; class RequiredSimpleKeyNotFound: public Exception {}; + class ZeroIndentationInBlockScalar: public Exception {}; + class UnexpectedCharacterInBlockScalar: public Exception {}; class UnknownEscapeSequence: public Exception { public: diff --git a/exp.h b/exp.h index 3ad948f..3dcbdb2 100644 --- a/exp.h +++ b/exp.h @@ -43,6 +43,9 @@ namespace YAML const RegEx EscSingleQuote = RegEx("\'\'"); const RegEx EscBreak = RegEx('\\') + Break; + const RegEx ChompIndicator = RegEx("+-", REGEX_OR); + const RegEx Chomp = (ChompIndicator + Digit) || (Digit + ChompIndicator) || ChompIndicator || Digit; + // and some functions std::string Escape(std::istream& in, int& length); } diff --git a/scanner.cpp b/scanner.cpp index d785706..1237a60 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -31,8 +31,8 @@ namespace YAML // . Extracts a character from the stream and updates our position char Scanner::GetChar() { - m_column++; char ch = INPUT.get(); + m_column++; if(ch == '\n') { m_column = 0; m_line++; @@ -201,12 +201,9 @@ namespace YAML // TODO: alias/anchor/tag - // TODO: special scalars - if(INPUT.peek() == Keys::LiteralScalar && m_flowLevel == 0) - return; - - if(INPUT.peek() == Keys::FoldedScalar && m_flowLevel == 0) - return; + // special scalars + if(m_flowLevel == 0 && (INPUT.peek() == Keys::LiteralScalar || INPUT.peek() == Keys::FoldedScalar)) + return ScanAndEnqueue(new BlockScalarToken); if(INPUT.peek() == '\'' || INPUT.peek() == '\"') return ScanAndEnqueue(new QuotedScalarToken); diff --git a/scanner.h b/scanner.h index 8d0033b..b83b8a2 100644 --- a/scanner.h +++ b/scanner.h @@ -45,15 +45,20 @@ namespace YAML bool IsValue(); bool IsPlainScalar(); + void GetBlockIndentation(int& indent, std::string& breaks); + struct WhitespaceInfo { WhitespaceInfo(); + void SetChompers(char ch); void AddBlank(char ch); void AddBreak(const std::string& line); - std::string Join(); + std::string Join(bool lastline = false); bool leadingBlanks; + bool fold; std::string whitespace, leadingBreaks, trailingBreaks; + int chomp, increment; }; struct SimpleKey { diff --git a/scantoken.cpp b/scantoken.cpp index 0cc741e..6cd08d2 100644 --- a/scantoken.cpp +++ b/scantoken.cpp @@ -358,13 +358,137 @@ namespace YAML return pToken; } + // BlockScalarToken + template <> BlockScalarToken *Scanner::ScanToken(BlockScalarToken *pToken) + { + // simple keys always ok after block scalars (since we're gonna start a new line anyways) + m_simpleKeyAllowed = true; + + WhitespaceInfo info; + + // eat block indicator ('|' or '>') + char indicator = GetChar(); + info.fold = (indicator == Keys::FoldedScalar); + + // eat chomping/indentation indicators + int n = Exp::Chomp.Match(INPUT); + for(int i=0;i= 0) + indent += m_indents.top(); + + // finally, grab that scalar + std::string scalar; + while(INPUT) { + // initialize indentation + GetBlockIndentation(indent, info.trailingBreaks); + + // are we done with this guy (i.e. at a lower indentation?) + if(m_column != indent) + break; + + bool trailingBlank = Exp::Blank.Matches(INPUT); + scalar += info.Join(); + + bool leadingBlank = Exp::Blank.Matches(INPUT); + + // now eat and save the line + while(INPUT.peek() != EOF && !Exp::Break.Matches(INPUT)) + scalar += GetChar(); + + // we know it's a line break; see how many characters to read + int n = Exp::Break.Match(INPUT); + std::string line = GetChar(n); + info.AddBreak(line); + } + + // one last whitespace join (with chompers this time) + scalar += info.Join(true); + + // finally set the scalar + pToken->value = scalar; + + return pToken; + } + + // GetBlockIndentation + // . Helper to scanning a block scalar. + // . Eats leading *indentation* zeros (i.e., those that come before 'indent'), + // and updates 'indent' (if it hasn't been set yet). + void Scanner::GetBlockIndentation(int& indent, std::string& breaks) + { + int maxIndent = 0; + + while(1) { + // eat as many indentation spaces as we can + while((indent == 0 || m_column < indent) && INPUT.peek() == ' ') + Eat(1); + + if(m_column > maxIndent) + maxIndent = m_column; + + // do we need more indentation, but we've got a tab? + if((indent == 0 || m_column < indent) && INPUT.peek() == '\t') + throw IllegalTabInScalar(); // TODO: are literal scalar lines allowed to have tabs here? + + // is this a non-empty line? + if(!Exp::Break.Matches(INPUT)) + break; + + // otherwise, eat the line break and move on + int n = Exp::Break.Match(INPUT); + breaks += GetChar(n); + } + + // finally, set the indentation + if(indent == 0) { + indent = maxIndent; + if(indent < m_indents.top() + 1) + indent = m_indents.top() + 1; + if(indent < 1) + indent = 1; + } + } + ////////////////////////////////////////////////////////// // WhitespaceInfo stuff - Scanner::WhitespaceInfo::WhitespaceInfo(): leadingBlanks(false) + Scanner::WhitespaceInfo::WhitespaceInfo(): leadingBlanks(false), fold(true), chomp(0), increment(0) { } + void Scanner::WhitespaceInfo::SetChompers(char ch) + { + if(ch == '+') + chomp = 1; + else if(ch == '-') + chomp = -1; + else if(Exp::Digit.Matches(ch)) { + increment = ch - '0'; + if(increment == 0) + throw ZeroIndentationInBlockScalar(); + } + } + void Scanner::WhitespaceInfo::AddBlank(char ch) { if(!leadingBlanks) @@ -382,20 +506,19 @@ namespace YAML trailingBreaks += line; } - std::string Scanner::WhitespaceInfo::Join() + std::string Scanner::WhitespaceInfo::Join(bool lastLine) { std::string ret; if(leadingBlanks) { - if(Exp::Break.Matches(leadingBreaks)) { - // fold line break? - if(trailingBreaks.empty()) - ret = " "; - else - ret = trailingBreaks; - } else { - ret = leadingBreaks + trailingBreaks; - } + // fold line break? + if(fold && Exp::Break.Matches(leadingBreaks) && trailingBreaks.empty() && !lastLine) + ret = " "; + else if(!lastLine || chomp != -1) + ret = leadingBreaks; + + if(!lastLine || chomp == 1) + ret += trailingBreaks; leadingBlanks = false; leadingBreaks = ""; diff --git a/test.yaml b/test.yaml index 3cb65c2..82533b5 100644 --- a/test.yaml +++ b/test.yaml @@ -1,4 +1,3 @@ -{ - a simple key: a value, - ? a complex key: another value, -} \ No newline at end of file +- sun: yellow +- ? earth: blue + : moon: white \ No newline at end of file diff --git a/token.h b/token.h index fec77d2..1ab6571 100644 --- a/token.h +++ b/token.h @@ -39,4 +39,5 @@ namespace YAML struct PlainScalarToken: public ScalarToken {}; struct QuotedScalarToken: public ScalarToken {}; + struct BlockScalarToken: public ScalarToken {}; } From 34cd7177cdcfa9b6147136e227efe2b151fd7f4b Mon Sep 17 00:00:00 2001 From: beder Date: Sat, 28 Jun 2008 20:09:49 +0000 Subject: [PATCH 019/295] --- test.yaml | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 97 insertions(+), 3 deletions(-) diff --git a/test.yaml b/test.yaml index 82533b5..8a9714c 100644 --- a/test.yaml +++ b/test.yaml @@ -1,3 +1,97 @@ -- sun: yellow -- ? earth: blue - : moon: white \ No newline at end of file +--- +model: + file: data/models/compound.model + textures: data/materials/compound +rooms: + - name: "Room #1" + pos: [0, 0, 0] + size: [1000, 1000, 500] + height: 500 + stairtype: none + display: [] + pathfinding: + tilesize: 50 + size: [24, 24] + map: | + ----------------------- + -+++++++++++++++++++++- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+--------------------- + -+--------------------- + -+--------------------- + -+--------------------- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+++++++++++++++++++++- + ----------------------- + - name: Doorway + pos: [1000, 400, 0] + size: [50, 200, 500] + height: 500 + stairtype: none + display: [] + pathfinding: + tilesize: 50 + size: [5, 9] + map: | + ----- + -+++- + ----- + ----- + ----- + ----- + ----- + -+++- + ----- + - name: "Room #2" + pos: [1050, 0, 0] + size: [1000, 1000, 500] + height: 500 + stairtype: none + display: [] + pathfinding: + tilesize: 50 + size: [24, 24] + map: | + ----------------------- + -+++++++++++++++++++++- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + ---------------------+- + ---------------------+- + ---------------------+- + ---------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+++++++++++++++++++++- + ----------------------- +exits: + - room1: "Room #1" + room2: "Room #2" + dir: e + pos: [400, 600] From ab27b9781e553e632d97435e152f8ae3cc13baa6 Mon Sep 17 00:00:00 2001 From: beder Date: Sat, 28 Jun 2008 22:05:51 +0000 Subject: [PATCH 020/295] Small refactoring. --- exceptions.h | 1 + scanner.cpp | 16 ---------------- scanner.h | 2 -- scantoken.cpp | 43 +++++++++++++++++++------------------------ 4 files changed, 20 insertions(+), 42 deletions(-) diff --git a/exceptions.h b/exceptions.h index 1e0867b..3540519 100644 --- a/exceptions.h +++ b/exceptions.h @@ -12,6 +12,7 @@ namespace YAML class IllegalMapValue: public Exception {}; class IllegalScalar: public Exception {}; class IllegalTabInScalar: public Exception {}; + class IllegalFlowEnd: public Exception {}; class DocIndicatorInQuote: public Exception {}; class EOFInQuote: public Exception {}; class RequiredSimpleKeyNotFound: public Exception {}; diff --git a/scanner.cpp b/scanner.cpp index 1237a60..7c77b52 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -288,22 +288,6 @@ namespace YAML } } - // IncreaseFlowLevel - void Scanner::IncreaseFlowLevel() - { - // TODO: Push simple key - m_flowLevel++; - } - - // DecreaseFlowLevel - void Scanner::DecreaseFlowLevel() - { - if(m_flowLevel > 0) { - m_flowLevel--; - // TODO: Pop simple key - } - } - // GetNextToken // . Returns the next token on the queue, and scans if only we need to. Token *Scanner::GetNextToken() diff --git a/scanner.h b/scanner.h index b83b8a2..037b4b8 100644 --- a/scanner.h +++ b/scanner.h @@ -22,8 +22,6 @@ namespace YAML void ScanToNextToken(); Token *PushIndentTo(int column, bool sequence); void PopIndentTo(int column); - void IncreaseFlowLevel(); - void DecreaseFlowLevel(); void InsertSimpleKey(); bool ValidateSimpleKey(); diff --git a/scantoken.cpp b/scantoken.cpp index 6cd08d2..3b8d7ef 100644 --- a/scantoken.cpp +++ b/scantoken.cpp @@ -63,7 +63,7 @@ namespace YAML { // flow sequences can be simple keys InsertSimpleKey(); - IncreaseFlowLevel(); + m_flowLevel++; m_simpleKeyAllowed = true; // eat @@ -76,7 +76,7 @@ namespace YAML { // flow maps can be simple keys InsertSimpleKey(); - IncreaseFlowLevel(); + m_flowLevel++; m_simpleKeyAllowed = true; // eat @@ -87,8 +87,10 @@ namespace YAML // FlowSeqEndToken template <> FlowSeqEndToken *Scanner::ScanToken(FlowSeqEndToken *pToken) { -// ValidateSimpleKey(); - DecreaseFlowLevel(); + if(m_flowLevel == 0) + throw IllegalFlowEnd(); + + m_flowLevel--; m_simpleKeyAllowed = false; // eat @@ -99,8 +101,10 @@ namespace YAML // FlowMapEndToken template <> FlowMapEndToken *Scanner::ScanToken(FlowMapEndToken *pToken) { - //ValidateSimpleKey(); - DecreaseFlowLevel(); + if(m_flowLevel == 0) + throw IllegalFlowEnd(); + + m_flowLevel--; m_simpleKeyAllowed = false; // eat @@ -111,7 +115,6 @@ namespace YAML // FlowEntryToken template <> FlowEntryToken *Scanner::ScanToken(FlowEntryToken *pToken) { - //ValidateSimpleKey(); m_simpleKeyAllowed = true; // eat @@ -122,19 +125,15 @@ namespace YAML // BlockEntryToken template <> BlockEntryToken *Scanner::ScanToken(BlockEntryToken *pToken) { - //ValidateSimpleKey(); - // we better be in the block context! - if(m_flowLevel == 0) { - // can we put it here? - if(!m_simpleKeyAllowed) - throw IllegalBlockEntry(); + if(m_flowLevel > 0) + throw IllegalBlockEntry(); - PushIndentTo(m_column, true); // , -1 - } else { - // TODO: throw? - } + // can we put it here? + if(!m_simpleKeyAllowed) + throw IllegalBlockEntry(); + PushIndentTo(m_column, true); m_simpleKeyAllowed = true; // eat @@ -145,7 +144,7 @@ namespace YAML // KeyToken template <> KeyToken *Scanner::ScanToken(KeyToken *pToken) { - // are we in block context? + // handle keys diffently in the block context (and manage indents) if(m_flowLevel == 0) { if(!m_simpleKeyAllowed) throw IllegalMapKey(); @@ -153,8 +152,6 @@ namespace YAML PushIndentTo(m_column, false); } - // TODO: "remove simple key" - // can only put a simple key here if we're in block context if(m_flowLevel == 0) m_simpleKeyAllowed = true; @@ -170,13 +167,11 @@ namespace YAML template <> ValueToken *Scanner::ScanToken(ValueToken *pToken) { // does this follow a simple key? -// bool isValidKey = ValidateSimpleKey(); - if(m_isLastKeyValid) { // can't follow a simple key with another simple key (dunno why, though - it seems fine) m_simpleKeyAllowed = false; } else { - // are we in block context? + // handle values diffently in the block context (and manage indents) if(m_flowLevel == 0) { if(!m_simpleKeyAllowed) throw IllegalMapValue(); @@ -393,7 +388,7 @@ namespace YAML // set the initial indentation int indent = info.increment; - if(info.increment && m_indents.top() >= 0) + if(info.increment && m_indents.top() >= 0) indent += m_indents.top(); // finally, grab that scalar From 45dfc719e1eb9eda5aa04f4f638d71aa499d4110 Mon Sep 17 00:00:00 2001 From: beder Date: Sun, 29 Jun 2008 00:33:34 +0000 Subject: [PATCH 021/295] --- exceptions.h | 2 + exp.h | 3 ++ scanner.cpp | 27 +++++++++---- scantoken.cpp | 30 ++++++++++++++ test.yaml | 110 ++++++-------------------------------------------- token.h | 6 +++ 6 files changed, 74 insertions(+), 104 deletions(-) diff --git a/exceptions.h b/exceptions.h index 3540519..f8968b7 100644 --- a/exceptions.h +++ b/exceptions.h @@ -18,6 +18,8 @@ namespace YAML class RequiredSimpleKeyNotFound: public Exception {}; class ZeroIndentationInBlockScalar: public Exception {}; class UnexpectedCharacterInBlockScalar: public Exception {}; + class AnchorNotFound: public Exception {}; + class IllegalCharacterInAnchor: public Exception {}; class UnknownEscapeSequence: public Exception { public: diff --git a/exp.h b/exp.h index 3dcbdb2..cc308be 100644 --- a/exp.h +++ b/exp.h @@ -16,6 +16,8 @@ namespace YAML const RegEx Break = RegEx('\n'); const RegEx BlankOrBreak = Blank || Break; const RegEx Digit = RegEx('0', '9'); + const RegEx Alpha = RegEx('a', 'z') || RegEx('A', 'Z'); + const RegEx AlphaNumeric = Alpha || Digit; const RegEx Hex = Digit || RegEx('A', 'F') || RegEx('a', 'f'); // actual tags @@ -28,6 +30,7 @@ namespace YAML const RegEx Value = RegEx(':'), ValueInFlow = RegEx(':') + BlankOrBreak; const RegEx Comment = RegEx('#'); + const RegEx AnchorEnd = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak; // Plain scalar rules: // . Cannot start with a blank. diff --git a/scanner.cpp b/scanner.cpp index 7c77b52..bc7d2b5 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -148,9 +148,9 @@ namespace YAML m_limboTokens.erase(pToken); } - /////////////////////////////////////////////////////////////////////// - // The main scanning function - + // ScanNextToken + // . The main scanning function; here we branch out and + // scan whatever the next token should be. void Scanner::ScanNextToken() { if(m_endedStream) @@ -159,21 +159,31 @@ namespace YAML if(!m_startedStream) return ScanAndEnqueue(new StreamStartToken); + // get rid of whitespace, etc. (in between tokens it should be irrelevent) ScanToNextToken(); + + // check the latest simple key ValidateSimpleKey(); + + // maybe need to end some blocks PopIndentTo(m_column); + // ***** + // And now branch based on the next few characters! + // ***** + + // end of stream if(INPUT.peek() == EOF) return ScanAndEnqueue(new StreamEndToken); - // are we at a document token? + // document token if(IsDocumentStart()) return ScanAndEnqueue(new DocumentStartToken); if(IsDocumentEnd()) return ScanAndEnqueue(new DocumentEndToken); - // are we at a flow start/end/entry? + // flow start/end/entry if(INPUT.peek() == Keys::FlowSeqStart) return ScanAndEnqueue(new FlowSeqStartToken); @@ -189,7 +199,7 @@ namespace YAML if(INPUT.peek() == Keys::FlowEntry) return ScanAndEnqueue(new FlowEntryToken); - // block/map stuff? + // block/map stuff if(IsBlockEntry()) return ScanAndEnqueue(new BlockEntryToken); @@ -199,7 +209,10 @@ namespace YAML if(IsValue()) return ScanAndEnqueue(new ValueToken); - // TODO: alias/anchor/tag + if(INPUT.peek() == Keys::Alias || INPUT.peek() == Keys::Anchor) + return ScanAndEnqueue(new AnchorToken); + + // TODO: tag // special scalars if(m_flowLevel == 0 && (INPUT.peek() == Keys::LiteralScalar || INPUT.peek() == Keys::FoldedScalar)) diff --git a/scantoken.cpp b/scantoken.cpp index 3b8d7ef..c81feb8 100644 --- a/scantoken.cpp +++ b/scantoken.cpp @@ -191,6 +191,36 @@ namespace YAML return pToken; } + // AnchorToken + template <> AnchorToken *Scanner::ScanToken(AnchorToken *pToken) + { + // insert a potential simple key + if(m_simpleKeyAllowed) + InsertSimpleKey(); + m_simpleKeyAllowed = false; + + // eat the indicator + char indicator = GetChar(); + pToken->alias = (indicator == Keys::Alias); + + // now eat the content + std::string tag; + while(Exp::AlphaNumeric.Matches(INPUT)) + tag += GetChar(); + + // we need to have read SOMETHING! + if(tag.empty()) + throw AnchorNotFound(); + + // and needs to end correctly + if(INPUT.peek() != EOF && !Exp::AnchorEnd.Matches(INPUT)) + throw IllegalCharacterInAnchor(); + + // and we're done + pToken->value = tag; + return pToken; + } + // PlainScalarToken // . We scan these in passes of two steps each: First, grab all non-whitespace // characters we can, and then grab all whitespace characters we can. diff --git a/test.yaml b/test.yaml index 8a9714c..9dfb8de 100644 --- a/test.yaml +++ b/test.yaml @@ -1,97 +1,13 @@ ---- -model: - file: data/models/compound.model - textures: data/materials/compound -rooms: - - name: "Room #1" - pos: [0, 0, 0] - size: [1000, 1000, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [24, 24] - map: | - ----------------------- - -+++++++++++++++++++++- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+--------------------- - -+--------------------- - -+--------------------- - -+--------------------- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+++++++++++++++++++++- - ----------------------- - - name: Doorway - pos: [1000, 400, 0] - size: [50, 200, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [5, 9] - map: | - ----- - -+++- - ----- - ----- - ----- - ----- - ----- - -+++- - ----- - - name: "Room #2" - pos: [1050, 0, 0] - size: [1000, 1000, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [24, 24] - map: | - ----------------------- - -+++++++++++++++++++++- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - ---------------------+- - ---------------------+- - ---------------------+- - ---------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+++++++++++++++++++++- - ----------------------- -exits: - - room1: "Room #1" - room2: "Room #2" - dir: e - pos: [400, 600] +people: + - &jsb + name: Jesse + age: 23 + - &dab + name: Daniel + age: 25 + - &ncb + name: Naftali + age: 21 +students: + - *jsb + - *ncb \ No newline at end of file diff --git a/token.h b/token.h index 1ab6571..93e83a6 100644 --- a/token.h +++ b/token.h @@ -31,6 +31,12 @@ namespace YAML struct KeyToken: public Token {}; struct ValueToken: public Token {}; + struct AnchorToken: public Token { + bool alias; + std::string value; + + virtual void Write(std::ostream& out) const { out << (alias ? '*' : '&') << value; } + }; struct ScalarToken: public Token { std::string value; From 3c56fd49eb8e10de09201f6b5cd6a31a7f7d9b6a Mon Sep 17 00:00:00 2001 From: beder Date: Sun, 29 Jun 2008 03:11:25 +0000 Subject: [PATCH 022/295] Moved the scalar-related functions to their own file. --- scanner.h | 14 -- scanscalar.cpp | 343 +++++++++++++++++++++++++++++++++++++++++++++ scanscalar.h | 20 +++ scantoken.cpp | 335 ------------------------------------------- test.yaml | 4 +- token.h | 6 +- yaml-reader.vcproj | 8 ++ 7 files changed, 378 insertions(+), 352 deletions(-) create mode 100644 scanscalar.cpp create mode 100644 scanscalar.h diff --git a/scanner.h b/scanner.h index 037b4b8..7f06269 100644 --- a/scanner.h +++ b/scanner.h @@ -45,20 +45,6 @@ namespace YAML void GetBlockIndentation(int& indent, std::string& breaks); - struct WhitespaceInfo { - WhitespaceInfo(); - - void SetChompers(char ch); - void AddBlank(char ch); - void AddBreak(const std::string& line); - std::string Join(bool lastline = false); - - bool leadingBlanks; - bool fold; - std::string whitespace, leadingBreaks, trailingBreaks; - int chomp, increment; - }; - struct SimpleKey { SimpleKey(int pos_, int line_, int column_, int flowLevel_); diff --git a/scanscalar.cpp b/scanscalar.cpp new file mode 100644 index 0000000..30744ed --- /dev/null +++ b/scanscalar.cpp @@ -0,0 +1,343 @@ +#include "scanscalar.h" +#include "scanner.h" +#include "exp.h" +#include "exceptions.h" +#include "token.h" + +namespace YAML +{ + ////////////////////////////////////////////////////////// + // WhitespaceInfo + + WhitespaceInfo::WhitespaceInfo(): leadingBlanks(false), fold(true), chomp(0), increment(0) + { + } + + void WhitespaceInfo::SetChompers(char ch) + { + if(ch == '+') + chomp = 1; + else if(ch == '-') + chomp = -1; + else if(Exp::Digit.Matches(ch)) { + increment = ch - '0'; + if(increment == 0) + throw ZeroIndentationInBlockScalar(); + } + } + + void WhitespaceInfo::AddBlank(char ch) + { + if(!leadingBlanks) + whitespace += ch; + } + + void WhitespaceInfo::AddBreak(const std::string& line) + { + // where to store this character? + if(!leadingBlanks) { + leadingBlanks = true; + whitespace = ""; + leadingBreaks += line; + } else + trailingBreaks += line; + } + + std::string WhitespaceInfo::Join(bool lastLine) + { + std::string ret; + + if(leadingBlanks) { + // fold line break? + if(fold && Exp::Break.Matches(leadingBreaks) && trailingBreaks.empty() && !lastLine) + ret = " "; + else if(!lastLine || chomp != -1) + ret = leadingBreaks; + + if(!lastLine || chomp == 1) + ret += trailingBreaks; + + leadingBlanks = false; + leadingBreaks = ""; + trailingBreaks = ""; + } else if(!whitespace.empty()) { + ret = whitespace; + whitespace = ""; + } + + return ret; + } + + // PlainScalarToken + // . We scan these in passes of two steps each: First, grab all non-whitespace + // characters we can, and then grab all whitespace characters we can. + // . This has the benefit of letting us handle leading whitespace (which is chomped) + // and in-line whitespace (which is kept) separately. + template <> PlainScalarToken *Scanner::ScanToken(PlainScalarToken *pToken) + { + // insert a potential simple key + if(m_simpleKeyAllowed) + InsertSimpleKey(); + m_simpleKeyAllowed = false; + + // now eat and store the scalar + std::string scalar; + WhitespaceInfo info; + + while(INPUT) { + // doc start/end tokens + if(IsDocumentStart() || IsDocumentEnd()) + break; + + // comment + if(Exp::Comment.Matches(INPUT)) + break; + + // first eat non-blanks + while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) { + // illegal colon in flow context + if(m_flowLevel > 0 && Exp::IllegalColonInScalar.Matches(INPUT)) + throw IllegalScalar(); + + // characters that might end the scalar + if(m_flowLevel > 0 && Exp::EndScalarInFlow.Matches(INPUT)) + break; + if(m_flowLevel == 0 && Exp::EndScalar.Matches(INPUT)) + break; + + // finally, read the character! + scalar += GetChar(); + } + + // did we hit a non-blank character that ended us? + if(!Exp::BlankOrBreak.Matches(INPUT)) + break; + + // now eat blanks + while(INPUT && Exp::BlankOrBreak.Matches(INPUT)) { + if(Exp::Blank.Matches(INPUT)) { + // can't use tabs as indentation! only spaces! + if(INPUT.peek() == '\t' && info.leadingBlanks && m_column <= m_indents.top()) + throw IllegalTabInScalar(); + + info.AddBlank(GetChar()); + } else { + // we know it's a line break; see how many characters to read + int n = Exp::Break.Match(INPUT); + std::string line = GetChar(n); + info.AddBreak(line); + + // and we can't continue a simple key to the next line + ValidateSimpleKey(); + } + } + + // break if we're below the indentation level + if(m_flowLevel == 0 && m_column <= m_indents.top()) + break; + + // finally join whitespace + scalar += info.Join(); + } + + // now modify our token + pToken->value = scalar; + if(info.leadingBlanks) + m_simpleKeyAllowed = true; + + return pToken; + } + + // QuotedScalarToken + template <> QuotedScalarToken *Scanner::ScanToken(QuotedScalarToken *pToken) + { + // insert a potential simple key + if(m_simpleKeyAllowed) + InsertSimpleKey(); + m_simpleKeyAllowed = false; + + // eat single or double quote + char quote = GetChar(); + pToken->single = (quote == '\''); + + // now eat and store the scalar + std::string scalar; + WhitespaceInfo info; + + while(INPUT) { + if(IsDocumentStart() || IsDocumentEnd()) + throw DocIndicatorInQuote(); + + if(INPUT.peek() == EOF) + throw EOFInQuote(); + + // first eat non-blanks + while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) { + // escaped single quote? + if(pToken->single && Exp::EscSingleQuote.Matches(INPUT)) { + int n = Exp::EscSingleQuote.Match(INPUT); + scalar += GetChar(n); + continue; + } + + // is the quote ending? + if(INPUT.peek() == quote) + break; + + // escaped newline? + if(Exp::EscBreak.Matches(INPUT)) + break; + + // other escape sequence + if(INPUT.peek() == '\\') { + int length = 0; + scalar += Exp::Escape(INPUT, length); + m_column += length; + continue; + } + + // and finally, just add the damn character + scalar += GetChar(); + } + + // is the quote ending? + if(INPUT.peek() == quote) { + // eat and go + GetChar(); + break; + } + + // now we eat blanks + while(Exp::BlankOrBreak.Matches(INPUT)) { + if(Exp::Blank.Matches(INPUT)) { + info.AddBlank(GetChar()); + } else { + // we know it's a line break; see how many characters to read + int n = Exp::Break.Match(INPUT); + std::string line = GetChar(n); + info.AddBreak(line); + + // and we can't continue a simple key to the next line + ValidateSimpleKey(); + } + } + + // and finally join the whitespace + scalar += info.Join(); + } + + pToken->value = scalar; + return pToken; + } + + // BlockScalarToken + template <> BlockScalarToken *Scanner::ScanToken(BlockScalarToken *pToken) + { + // simple keys always ok after block scalars (since we're gonna start a new line anyways) + m_simpleKeyAllowed = true; + + WhitespaceInfo info; + + // eat block indicator ('|' or '>') + char indicator = GetChar(); + info.fold = (indicator == Keys::FoldedScalar); + + // eat chomping/indentation indicators + int n = Exp::Chomp.Match(INPUT); + for(int i=0;i= 0) + indent += m_indents.top(); + + // finally, grab that scalar + std::string scalar; + while(INPUT) { + // initialize indentation + GetBlockIndentation(indent, info.trailingBreaks); + + // are we done with this guy (i.e. at a lower indentation?) + if(m_column != indent) + break; + + bool trailingBlank = Exp::Blank.Matches(INPUT); + scalar += info.Join(); + + bool leadingBlank = Exp::Blank.Matches(INPUT); + + // now eat and save the line + while(INPUT.peek() != EOF && !Exp::Break.Matches(INPUT)) + scalar += GetChar(); + + // we know it's a line break; see how many characters to read + int n = Exp::Break.Match(INPUT); + std::string line = GetChar(n); + info.AddBreak(line); + } + + // one last whitespace join (with chompers this time) + scalar += info.Join(true); + + // finally set the scalar + pToken->value = scalar; + + return pToken; + } + + // GetBlockIndentation + // . Helper to scanning a block scalar. + // . Eats leading *indentation* zeros (i.e., those that come before 'indent'), + // and updates 'indent' (if it hasn't been set yet). + void Scanner::GetBlockIndentation(int& indent, std::string& breaks) + { + int maxIndent = 0; + + while(1) { + // eat as many indentation spaces as we can + while((indent == 0 || m_column < indent) && INPUT.peek() == ' ') + Eat(1); + + if(m_column > maxIndent) + maxIndent = m_column; + + // do we need more indentation, but we've got a tab? + if((indent == 0 || m_column < indent) && INPUT.peek() == '\t') + throw IllegalTabInScalar(); // TODO: are literal scalar lines allowed to have tabs here? + + // is this a non-empty line? + if(!Exp::Break.Matches(INPUT)) + break; + + // otherwise, eat the line break and move on + int n = Exp::Break.Match(INPUT); + breaks += GetChar(n); + } + + // finally, set the indentation + if(indent == 0) { + indent = maxIndent; + if(indent < m_indents.top() + 1) + indent = m_indents.top() + 1; + if(indent < 1) + indent = 1; + } + } +} diff --git a/scanscalar.h b/scanscalar.h new file mode 100644 index 0000000..d63831b --- /dev/null +++ b/scanscalar.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace YAML +{ + struct WhitespaceInfo { + WhitespaceInfo(); + + void SetChompers(char ch); + void AddBlank(char ch); + void AddBreak(const std::string& line); + std::string Join(bool lastline = false); + + bool leadingBlanks; + bool fold; + std::string whitespace, leadingBreaks, trailingBreaks; + int chomp, increment; + }; +} diff --git a/scantoken.cpp b/scantoken.cpp index c81feb8..5f9bcc0 100644 --- a/scantoken.cpp +++ b/scantoken.cpp @@ -220,339 +220,4 @@ namespace YAML pToken->value = tag; return pToken; } - - // PlainScalarToken - // . We scan these in passes of two steps each: First, grab all non-whitespace - // characters we can, and then grab all whitespace characters we can. - // . This has the benefit of letting us handle leading whitespace (which is chomped) - // and in-line whitespace (which is kept) separately. - template <> PlainScalarToken *Scanner::ScanToken(PlainScalarToken *pToken) - { - // insert a potential simple key - if(m_simpleKeyAllowed) - InsertSimpleKey(); - m_simpleKeyAllowed = false; - - // now eat and store the scalar - std::string scalar; - WhitespaceInfo info; - - while(INPUT) { - // doc start/end tokens - if(IsDocumentStart() || IsDocumentEnd()) - break; - - // comment - if(Exp::Comment.Matches(INPUT)) - break; - - // first eat non-blanks - while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) { - // illegal colon in flow context - if(m_flowLevel > 0 && Exp::IllegalColonInScalar.Matches(INPUT)) - throw IllegalScalar(); - - // characters that might end the scalar - if(m_flowLevel > 0 && Exp::EndScalarInFlow.Matches(INPUT)) - break; - if(m_flowLevel == 0 && Exp::EndScalar.Matches(INPUT)) - break; - - // finally, read the character! - scalar += GetChar(); - } - - // did we hit a non-blank character that ended us? - if(!Exp::BlankOrBreak.Matches(INPUT)) - break; - - // now eat blanks - while(INPUT && Exp::BlankOrBreak.Matches(INPUT)) { - if(Exp::Blank.Matches(INPUT)) { - // can't use tabs as indentation! only spaces! - if(INPUT.peek() == '\t' && info.leadingBlanks && m_column <= m_indents.top()) - throw IllegalTabInScalar(); - - info.AddBlank(GetChar()); - } else { - // we know it's a line break; see how many characters to read - int n = Exp::Break.Match(INPUT); - std::string line = GetChar(n); - info.AddBreak(line); - - // and we can't continue a simple key to the next line - ValidateSimpleKey(); - } - } - - // break if we're below the indentation level - if(m_flowLevel == 0 && m_column <= m_indents.top()) - break; - - // finally join whitespace - scalar += info.Join(); - } - - // now modify our token - pToken->value = scalar; - if(info.leadingBlanks) - m_simpleKeyAllowed = true; - - return pToken; - } - - // QuotedScalarToken - template <> QuotedScalarToken *Scanner::ScanToken(QuotedScalarToken *pToken) - { - // insert a potential simple key - if(m_simpleKeyAllowed) - InsertSimpleKey(); - m_simpleKeyAllowed = false; - - // eat single or double quote - char quote = GetChar(); - bool single = (quote == '\''); - - // now eat and store the scalar - std::string scalar; - WhitespaceInfo info; - - while(INPUT) { - if(IsDocumentStart() || IsDocumentEnd()) - throw DocIndicatorInQuote(); - - if(INPUT.peek() == EOF) - throw EOFInQuote(); - - // first eat non-blanks - while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) { - // escaped single quote? - if(single && Exp::EscSingleQuote.Matches(INPUT)) { - int n = Exp::EscSingleQuote.Match(INPUT); - scalar += GetChar(n); - continue; - } - - // is the quote ending? - if(INPUT.peek() == (single ? '\'' : '\"')) - break; - - // escaped newline? - if(Exp::EscBreak.Matches(INPUT)) - break; - - // other escape sequence - if(INPUT.peek() == '\\') { - int length = 0; - scalar += Exp::Escape(INPUT, length); - m_column += length; - continue; - } - - // and finally, just add the damn character - scalar += GetChar(); - } - - // is the quote ending? - if(INPUT.peek() == (single ? '\'' : '\"')) { - // eat and go - GetChar(); - break; - } - - // now we eat blanks - while(Exp::BlankOrBreak.Matches(INPUT)) { - if(Exp::Blank.Matches(INPUT)) { - info.AddBlank(GetChar()); - } else { - // we know it's a line break; see how many characters to read - int n = Exp::Break.Match(INPUT); - std::string line = GetChar(n); - info.AddBreak(line); - - // and we can't continue a simple key to the next line - ValidateSimpleKey(); - } - } - - // and finally join the whitespace - scalar += info.Join(); - } - - pToken->value = scalar; - return pToken; - } - - // BlockScalarToken - template <> BlockScalarToken *Scanner::ScanToken(BlockScalarToken *pToken) - { - // simple keys always ok after block scalars (since we're gonna start a new line anyways) - m_simpleKeyAllowed = true; - - WhitespaceInfo info; - - // eat block indicator ('|' or '>') - char indicator = GetChar(); - info.fold = (indicator == Keys::FoldedScalar); - - // eat chomping/indentation indicators - int n = Exp::Chomp.Match(INPUT); - for(int i=0;i= 0) - indent += m_indents.top(); - - // finally, grab that scalar - std::string scalar; - while(INPUT) { - // initialize indentation - GetBlockIndentation(indent, info.trailingBreaks); - - // are we done with this guy (i.e. at a lower indentation?) - if(m_column != indent) - break; - - bool trailingBlank = Exp::Blank.Matches(INPUT); - scalar += info.Join(); - - bool leadingBlank = Exp::Blank.Matches(INPUT); - - // now eat and save the line - while(INPUT.peek() != EOF && !Exp::Break.Matches(INPUT)) - scalar += GetChar(); - - // we know it's a line break; see how many characters to read - int n = Exp::Break.Match(INPUT); - std::string line = GetChar(n); - info.AddBreak(line); - } - - // one last whitespace join (with chompers this time) - scalar += info.Join(true); - - // finally set the scalar - pToken->value = scalar; - - return pToken; - } - - // GetBlockIndentation - // . Helper to scanning a block scalar. - // . Eats leading *indentation* zeros (i.e., those that come before 'indent'), - // and updates 'indent' (if it hasn't been set yet). - void Scanner::GetBlockIndentation(int& indent, std::string& breaks) - { - int maxIndent = 0; - - while(1) { - // eat as many indentation spaces as we can - while((indent == 0 || m_column < indent) && INPUT.peek() == ' ') - Eat(1); - - if(m_column > maxIndent) - maxIndent = m_column; - - // do we need more indentation, but we've got a tab? - if((indent == 0 || m_column < indent) && INPUT.peek() == '\t') - throw IllegalTabInScalar(); // TODO: are literal scalar lines allowed to have tabs here? - - // is this a non-empty line? - if(!Exp::Break.Matches(INPUT)) - break; - - // otherwise, eat the line break and move on - int n = Exp::Break.Match(INPUT); - breaks += GetChar(n); - } - - // finally, set the indentation - if(indent == 0) { - indent = maxIndent; - if(indent < m_indents.top() + 1) - indent = m_indents.top() + 1; - if(indent < 1) - indent = 1; - } - } - - ////////////////////////////////////////////////////////// - // WhitespaceInfo stuff - - Scanner::WhitespaceInfo::WhitespaceInfo(): leadingBlanks(false), fold(true), chomp(0), increment(0) - { - } - - void Scanner::WhitespaceInfo::SetChompers(char ch) - { - if(ch == '+') - chomp = 1; - else if(ch == '-') - chomp = -1; - else if(Exp::Digit.Matches(ch)) { - increment = ch - '0'; - if(increment == 0) - throw ZeroIndentationInBlockScalar(); - } - } - - void Scanner::WhitespaceInfo::AddBlank(char ch) - { - if(!leadingBlanks) - whitespace += ch; - } - - void Scanner::WhitespaceInfo::AddBreak(const std::string& line) - { - // where to store this character? - if(!leadingBlanks) { - leadingBlanks = true; - whitespace = ""; - leadingBreaks += line; - } else - trailingBreaks += line; - } - - std::string Scanner::WhitespaceInfo::Join(bool lastLine) - { - std::string ret; - - if(leadingBlanks) { - // fold line break? - if(fold && Exp::Break.Matches(leadingBreaks) && trailingBreaks.empty() && !lastLine) - ret = " "; - else if(!lastLine || chomp != -1) - ret = leadingBreaks; - - if(!lastLine || chomp == 1) - ret += trailingBreaks; - - leadingBlanks = false; - leadingBreaks = ""; - trailingBreaks = ""; - } else if(!whitespace.empty()) { - ret = whitespace; - whitespace = ""; - } - - return ret; - } } diff --git a/test.yaml b/test.yaml index 9dfb8de..98f6da4 100644 --- a/test.yaml +++ b/test.yaml @@ -3,10 +3,10 @@ people: name: Jesse age: 23 - &dab - name: Daniel + name: 'Daniel' age: 25 - &ncb - name: Naftali + name: "Naftali" age: 21 students: - *jsb diff --git a/token.h b/token.h index 93e83a6..8121817 100644 --- a/token.h +++ b/token.h @@ -44,6 +44,10 @@ namespace YAML }; struct PlainScalarToken: public ScalarToken {}; - struct QuotedScalarToken: public ScalarToken {}; + struct QuotedScalarToken: public ScalarToken { + bool single; + virtual void Write(std::ostream& out) const { out << (single ? '\'' : '\"') << value << (single ? '\'' : '\"'); } + }; + struct BlockScalarToken: public ScalarToken {}; } diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index b0c6da3..d68609b 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -201,6 +201,10 @@ RelativePath=".\scanner.cpp" > + + @@ -259,6 +263,10 @@ RelativePath=".\scanner.h" > + + From 8dfb5c0ea855777a58f45890dd0899d045605534 Mon Sep 17 00:00:00 2001 From: beder Date: Sun, 29 Jun 2008 05:45:41 +0000 Subject: [PATCH 023/295] Refactored common scalar scanning code (from plain, quoted, and block) to one function. --- exp.cpp | 10 +- regex.cpp | 49 +++++- regex.h | 8 +- scanner.h | 2 + scanscalar.cpp | 408 +++++++++++++++++++++++++++++-------------------- test.yaml | 17 +-- 6 files changed, 306 insertions(+), 188 deletions(-) diff --git a/exp.cpp b/exp.cpp index 07e4d2b..96ba91c 100644 --- a/exp.cpp +++ b/exp.cpp @@ -62,7 +62,7 @@ namespace YAML } // Escape - // . Escapes the sequence starting 'in' (it must begin with a '\') + // . Escapes the sequence starting 'in' (it must begin with a '\' or single quote) // and returns the result. // . Fills 'length' with how many characters we ate. // . Throws if it's an unknown escape character. @@ -72,10 +72,16 @@ namespace YAML length = 2; // eat slash - in.get(); + char escape = in.get(); // switch on escape character char ch = in.get(); + + // first do single quote, since it's easier + if(escape == '\'' && ch == '\'') + return "\'"; + + // now do the slash (we're not gonna check if it's a slash - you better pass one!) switch(ch) { case '0': return "\0"; case 'a': return "\x07"; diff --git a/regex.cpp b/regex.cpp index 342c0bd..040ccb9 100644 --- a/regex.cpp +++ b/regex.cpp @@ -53,6 +53,7 @@ namespace YAML case REGEX_MATCH: m_pOp = new MatchOperator; break; case REGEX_RANGE: m_pOp = new RangeOperator; break; case REGEX_OR: m_pOp = new OrOperator; break; + case REGEX_AND: m_pOp = new AndOperator; break; case REGEX_NOT: m_pOp = new NotOperator; break; case REGEX_SEQ: m_pOp = new SeqOperator; break; } @@ -80,19 +81,13 @@ namespace YAML // . Returns the number of characters matched. // . Returns -1 if no characters were matched (the reason for // not returning zero is that we may have an empty regex - // which SHOULD be considered successfully matching nothing, - // but that of course matches zero characters). + // which is ALWAYS successful at matching zero characters). int RegEx::Match(const std::string& str) const { if(!m_pOp) - return -1; + return 0; return m_pOp->Match(str, *this); - - //case REGEX_EMPTY: - // if(str.empty()) - // return 0; - // return -1; } // Match @@ -131,6 +126,14 @@ namespace YAML return ret; } + RegEx operator && (const RegEx& ex1, const RegEx& ex2) + { + RegEx ret(REGEX_AND); + ret.m_params.push_back(ex1); + ret.m_params.push_back(ex2); + return ret; + } + RegEx operator + (const RegEx& ex1, const RegEx& ex2) { RegEx ret(REGEX_SEQ); @@ -194,6 +197,36 @@ namespace YAML return -1; } + // AndOperator + // Note: 'AND' is a little funny, since we may be required to match things + // of different lengths. If we find a match, we return the length of + // the FIRST entry on the list. + int RegEx::AndOperator::Match(const std::string& str, const RegEx& regex) const + { + int first = -1; + for(unsigned i=0;i #include #include +#include "regex.h" namespace YAML { @@ -44,6 +45,7 @@ namespace YAML bool IsPlainScalar(); void GetBlockIndentation(int& indent, std::string& breaks); + std::string ScanScalar(RegEx end, bool eatEnd, int indent, char escape, bool fold, bool eatLeadingWhitespace, bool trimTrailingSpaces, int chomp); struct SimpleKey { SimpleKey(int pos_, int line_, int column_, int flowLevel_); diff --git a/scanscalar.cpp b/scanscalar.cpp index 30744ed..1a323ce 100644 --- a/scanscalar.cpp +++ b/scanscalar.cpp @@ -75,74 +75,77 @@ namespace YAML // and in-line whitespace (which is kept) separately. template <> PlainScalarToken *Scanner::ScanToken(PlainScalarToken *pToken) { + //// now eat and store the scalar + //std::string scalar; + //WhitespaceInfo info; + + //while(INPUT) { + // // doc start/end tokens + // if(IsDocumentStart() || IsDocumentEnd()) + // break; + + // // comment + // if(Exp::Comment.Matches(INPUT)) + // break; + + // // first eat non-blanks + // while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) { + // // illegal colon in flow context + // if(m_flowLevel > 0 && Exp::IllegalColonInScalar.Matches(INPUT)) + // throw IllegalScalar(); + + // // characters that might end the scalar + // if(m_flowLevel > 0 && Exp::EndScalarInFlow.Matches(INPUT)) + // break; + // if(m_flowLevel == 0 && Exp::EndScalar.Matches(INPUT)) + // break; + + // // finally, read the character! + // scalar += GetChar(); + // } + + // // did we hit a non-blank character that ended us? + // if(!Exp::BlankOrBreak.Matches(INPUT)) + // break; + + // // now eat blanks + // while(INPUT && Exp::BlankOrBreak.Matches(INPUT)) { + // if(Exp::Blank.Matches(INPUT)) { + // // can't use tabs as indentation! only spaces! + // if(INPUT.peek() == '\t' && info.leadingBlanks && m_column <= m_indents.top()) + // throw IllegalTabInScalar(); + + // info.AddBlank(GetChar()); + // } else { + // // we know it's a line break; see how many characters to read + // int n = Exp::Break.Match(INPUT); + // std::string line = GetChar(n); + // info.AddBreak(line); + + // // and we can't continue a simple key to the next line + // ValidateSimpleKey(); + // } + // } + + // // break if we're below the indentation level + // if(m_flowLevel == 0 && m_column <= m_indents.top()) + // break; + + // // finally join whitespace + // scalar += info.Join(); + //} + + RegEx end = (m_flowLevel > 0 ? Exp::EndScalarInFlow : Exp::EndScalar) || (RegEx(' ') + Exp::Comment); + int indent = (m_flowLevel > 0 ? 0 : m_indents.top() + 1); + // insert a potential simple key if(m_simpleKeyAllowed) InsertSimpleKey(); + + pToken->value = ScanScalar(end, false, indent, 0, true, true, true, 0); + m_simpleKeyAllowed = false; - - // now eat and store the scalar - std::string scalar; - WhitespaceInfo info; - - while(INPUT) { - // doc start/end tokens - if(IsDocumentStart() || IsDocumentEnd()) - break; - - // comment - if(Exp::Comment.Matches(INPUT)) - break; - - // first eat non-blanks - while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) { - // illegal colon in flow context - if(m_flowLevel > 0 && Exp::IllegalColonInScalar.Matches(INPUT)) - throw IllegalScalar(); - - // characters that might end the scalar - if(m_flowLevel > 0 && Exp::EndScalarInFlow.Matches(INPUT)) - break; - if(m_flowLevel == 0 && Exp::EndScalar.Matches(INPUT)) - break; - - // finally, read the character! - scalar += GetChar(); - } - - // did we hit a non-blank character that ended us? - if(!Exp::BlankOrBreak.Matches(INPUT)) - break; - - // now eat blanks - while(INPUT && Exp::BlankOrBreak.Matches(INPUT)) { - if(Exp::Blank.Matches(INPUT)) { - // can't use tabs as indentation! only spaces! - if(INPUT.peek() == '\t' && info.leadingBlanks && m_column <= m_indents.top()) - throw IllegalTabInScalar(); - - info.AddBlank(GetChar()); - } else { - // we know it's a line break; see how many characters to read - int n = Exp::Break.Match(INPUT); - std::string line = GetChar(n); - info.AddBreak(line); - - // and we can't continue a simple key to the next line - ValidateSimpleKey(); - } - } - - // break if we're below the indentation level - if(m_flowLevel == 0 && m_column <= m_indents.top()) - break; - - // finally join whitespace - scalar += info.Join(); - } - - // now modify our token - pToken->value = scalar; - if(info.leadingBlanks) + if(true/*info.leadingBlanks*/) m_simpleKeyAllowed = true; return pToken; @@ -151,91 +154,92 @@ namespace YAML // QuotedScalarToken template <> QuotedScalarToken *Scanner::ScanToken(QuotedScalarToken *pToken) { - // insert a potential simple key - if(m_simpleKeyAllowed) - InsertSimpleKey(); - m_simpleKeyAllowed = false; + //// now eat and store the scalar + //std::string scalar; + //WhitespaceInfo info; + + //while(INPUT) { + // if(IsDocumentStart() || IsDocumentEnd()) + // throw DocIndicatorInQuote(); + + // if(INPUT.peek() == EOF) + // throw EOFInQuote(); + + // // first eat non-blanks + // while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) { + // // escaped single quote? + // if(pToken->single && Exp::EscSingleQuote.Matches(INPUT)) { + // int n = Exp::EscSingleQuote.Match(INPUT); + // scalar += GetChar(n); + // continue; + // } + + // // is the quote ending? + // if(INPUT.peek() == quote) + // break; + + // // escaped newline? + // if(Exp::EscBreak.Matches(INPUT)) + // break; + + // // other escape sequence + // if(INPUT.peek() == '\\') { + // int length = 0; + // scalar += Exp::Escape(INPUT, length); + // m_column += length; + // continue; + // } + + // // and finally, just add the damn character + // scalar += GetChar(); + // } + + // // is the quote ending? + // if(INPUT.peek() == quote) { + // // eat and go + // GetChar(); + // break; + // } + + // // now we eat blanks + // while(Exp::BlankOrBreak.Matches(INPUT)) { + // if(Exp::Blank.Matches(INPUT)) { + // info.AddBlank(GetChar()); + // } else { + // // we know it's a line break; see how many characters to read + // int n = Exp::Break.Match(INPUT); + // std::string line = GetChar(n); + // info.AddBreak(line); + + // // and we can't continue a simple key to the next line + // ValidateSimpleKey(); + // } + // } + + // // and finally join the whitespace + // scalar += info.Join(); + //} // eat single or double quote char quote = GetChar(); pToken->single = (quote == '\''); - // now eat and store the scalar - std::string scalar; - WhitespaceInfo info; + RegEx end = (pToken->single ? RegEx(quote) && !Exp::EscSingleQuote : RegEx(quote)); + char escape = (pToken->single ? '\'' : '\\'); - while(INPUT) { - if(IsDocumentStart() || IsDocumentEnd()) - throw DocIndicatorInQuote(); + // insert a potential simple key + if(m_simpleKeyAllowed) + InsertSimpleKey(); - if(INPUT.peek() == EOF) - throw EOFInQuote(); + pToken->value = ScanScalar(end, true, 0, escape, true, true, false, 0); + m_simpleKeyAllowed = false; - // first eat non-blanks - while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) { - // escaped single quote? - if(pToken->single && Exp::EscSingleQuote.Matches(INPUT)) { - int n = Exp::EscSingleQuote.Match(INPUT); - scalar += GetChar(n); - continue; - } - - // is the quote ending? - if(INPUT.peek() == quote) - break; - - // escaped newline? - if(Exp::EscBreak.Matches(INPUT)) - break; - - // other escape sequence - if(INPUT.peek() == '\\') { - int length = 0; - scalar += Exp::Escape(INPUT, length); - m_column += length; - continue; - } - - // and finally, just add the damn character - scalar += GetChar(); - } - - // is the quote ending? - if(INPUT.peek() == quote) { - // eat and go - GetChar(); - break; - } - - // now we eat blanks - while(Exp::BlankOrBreak.Matches(INPUT)) { - if(Exp::Blank.Matches(INPUT)) { - info.AddBlank(GetChar()); - } else { - // we know it's a line break; see how many characters to read - int n = Exp::Break.Match(INPUT); - std::string line = GetChar(n); - info.AddBreak(line); - - // and we can't continue a simple key to the next line - ValidateSimpleKey(); - } - } - - // and finally join the whitespace - scalar += info.Join(); - } - - pToken->value = scalar; return pToken; } // BlockScalarToken template <> BlockScalarToken *Scanner::ScanToken(BlockScalarToken *pToken) { - // simple keys always ok after block scalars (since we're gonna start a new line anyways) - m_simpleKeyAllowed = true; - WhitespaceInfo info; // eat block indicator ('|' or '>') @@ -268,37 +272,13 @@ namespace YAML if(info.increment && m_indents.top() >= 0) indent += m_indents.top(); - // finally, grab that scalar - std::string scalar; - while(INPUT) { - // initialize indentation - GetBlockIndentation(indent, info.trailingBreaks); + GetBlockIndentation(indent, info.trailingBreaks); - // are we done with this guy (i.e. at a lower indentation?) - if(m_column != indent) - break; - - bool trailingBlank = Exp::Blank.Matches(INPUT); - scalar += info.Join(); - - bool leadingBlank = Exp::Blank.Matches(INPUT); - - // now eat and save the line - while(INPUT.peek() != EOF && !Exp::Break.Matches(INPUT)) - scalar += GetChar(); - - // we know it's a line break; see how many characters to read - int n = Exp::Break.Match(INPUT); - std::string line = GetChar(n); - info.AddBreak(line); - } - - // one last whitespace join (with chompers this time) - scalar += info.Join(true); - - // finally set the scalar - pToken->value = scalar; + bool eatLeadingWhitespace = false; + pToken->value = ScanScalar(RegEx(), false, indent, 0, info.fold, eatLeadingWhitespace, false, info.chomp); + // simple keys always ok after block scalars (since we're gonna start a new line anyways) + m_simpleKeyAllowed = true; return pToken; } @@ -340,4 +320,104 @@ namespace YAML indent = 1; } } + + // ScanScalar + std::string Scanner::ScanScalar(RegEx end, bool eatEnd, int indent, char escape, bool fold, bool eatLeadingWhitespace, bool trimTrailingSpaces, int chomp) + { + bool emptyLine = false, moreIndented = false; + std::string scalar; + + while(INPUT) { + // ******************************** + // Phase #1: scan until line ending + while(!end.Matches(INPUT) && !Exp::Break.Matches(INPUT)) { + if(INPUT.peek() == EOF) + break; + + // escaped newline? (only if we're escaping on slash) + if(escape == '\\' && Exp::EscBreak.Matches(INPUT)) { + int n = Exp::EscBreak.Match(INPUT); + Eat(n); + continue; + } + + // escape this? + if(INPUT.peek() == escape) { + int length = 0; + scalar += Exp::Escape(INPUT, length); + m_column += length; + continue; + } + + // otherwise, just add the damn character + scalar += GetChar(); + } + + // eof? if we're looking to eat something, then we throw + if(INPUT.peek() == EOF) { + if(eatEnd) + throw EOFInQuote(); + break; + } + + // are we done via character match? + int n = end.Match(INPUT); + if(n >= 0) { + if(eatEnd) + Eat(n); + break; + } + + // ******************************** + // Phase #2: eat line ending + n = Exp::Break.Match(INPUT); + Eat(n); + + // ******************************** + // Phase #3: scan initial spaces + + // first the required indentation + while(INPUT.peek() == ' ' && m_column < indent) + Eat(1); + + // and then the rest of the whitespace + if(eatLeadingWhitespace) { + while(Exp::Blank.Matches(INPUT)) + Eat(1); + } + + // was this an empty line? + bool nextEmptyLine = Exp::Break.Matches(INPUT); + bool nextMoreIndented = (INPUT.peek() == ' '); + + if(fold && !emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented) + scalar += " "; + else + scalar += "\n"; + + emptyLine = nextEmptyLine; + moreIndented = nextMoreIndented; + + // are we done via indentation? + if(!emptyLine && m_column < indent) + break; + } + + // post-processing + if(trimTrailingSpaces) { + unsigned pos = scalar.find_last_not_of(' '); + if(pos < scalar.size()) + scalar.erase(pos + 1); + } + + if(chomp <= 0) { + unsigned pos = scalar.find_last_not_of('\n'); + if(chomp == 0 && pos + 1 < scalar.size()) + scalar.erase(pos + 2); + else if(chomp == -1 && pos < scalar.size()) + scalar.erase(pos + 1); + } + + return scalar; + } } diff --git a/test.yaml b/test.yaml index 98f6da4..ee5d76e 100644 --- a/test.yaml +++ b/test.yaml @@ -1,13 +1,4 @@ -people: - - &jsb - name: Jesse - age: 23 - - &dab - name: 'Daniel' - age: 25 - - &ncb - name: "Naftali" - age: 21 -students: - - *jsb - - *ncb \ No newline at end of file +--- +- "quoted scalar that contains +--- + the document start!" \ No newline at end of file From 6efc5614ec0cff1199a674977dd7c063de28a2d2 Mon Sep 17 00:00:00 2001 From: beder Date: Sun, 29 Jun 2008 06:32:13 +0000 Subject: [PATCH 024/295] Moved the input stream, together with line/column info, into its own class, which allowed some other stuff just to pass the stream, and not have to be a member of Scanner. --- exp.cpp | 21 +++++++--------- exp.h | 3 ++- main.cpp | 16 ------------- scanner.cpp | 54 ++++++----------------------------------- scanner.h | 12 ++-------- scanscalar.cpp | 60 ++++++++++++++++++++++------------------------ scanscalar.h | 5 ++++ scantoken.cpp | 36 ++++++++++++++-------------- simplekey.cpp | 6 ++--- stream.cpp | 43 +++++++++++++++++++++++++++++++++ stream.h | 26 ++++++++++++++++++++ test.yaml | 14 ++++++++--- yaml-reader.vcproj | 8 +++++++ 13 files changed, 162 insertions(+), 142 deletions(-) create mode 100644 stream.cpp create mode 100644 stream.h diff --git a/exp.cpp b/exp.cpp index 96ba91c..f2b89d5 100644 --- a/exp.cpp +++ b/exp.cpp @@ -34,13 +34,12 @@ namespace YAML // Escape // . Translates the next 'codeLength' characters into a hex number and returns the result. // . Throws if it's not actually hex. - std::string Escape(std::istream& in, int& length, int codeLength) + std::string Escape(Stream& in, int codeLength) { // grab string - length += codeLength; std::string str; for(int i=0;i #include +#include "stream.h" namespace YAML { @@ -50,7 +51,7 @@ namespace YAML const RegEx Chomp = (ChompIndicator + Digit) || (Digit + ChompIndicator) || ChompIndicator || Digit; // and some functions - std::string Escape(std::istream& in, int& length); + std::string Escape(Stream& in); } namespace Keys diff --git a/main.cpp b/main.cpp index 6ff8af6..5e02ba3 100644 --- a/main.cpp +++ b/main.cpp @@ -3,22 +3,6 @@ int main() { - YAML::RegEx alpha = YAML::RegEx('a', 'z') || YAML::RegEx('A', 'Z'); - alpha.Matches("a"); - alpha.Matches("d"); - alpha.Matches("F"); - alpha.Matches("0"); - alpha.Matches("5"); - alpha.Matches(" "); - - YAML::RegEx blank = YAML::RegEx(' ') || YAML::RegEx('\t'); - YAML::RegEx docstart = YAML::RegEx("---") + (blank || YAML::RegEx(EOF) || YAML::RegEx()); - docstart.Matches("--- "); - docstart.Matches("... "); - docstart.Matches("----"); - docstart.Matches("---\t"); - docstart.Matches("---"); - YAML::Document doc("test.yaml"); return 0; diff --git a/scanner.cpp b/scanner.cpp index bc7d2b5..ace4995 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -7,8 +7,7 @@ namespace YAML { Scanner::Scanner(std::istream& in) - : INPUT(in), m_startedStream(false), m_endedStream(false), m_simpleKeyAllowed(false), m_flowLevel(0), - m_line(0), m_column(0) + : INPUT(in), m_startedStream(false), m_endedStream(false), m_simpleKeyAllowed(false), m_flowLevel(0) { } @@ -27,45 +26,6 @@ namespace YAML /////////////////////////////////////////////////////////////////////// // Misc. helpers - // GetChar - // . Extracts a character from the stream and updates our position - char Scanner::GetChar() - { - char ch = INPUT.get(); - m_column++; - if(ch == '\n') { - m_column = 0; - m_line++; - } - return ch; - } - - // GetChar - // . Extracts 'n' characters from the stream and updates our position - std::string Scanner::GetChar(int n) - { - std::string ret; - for(int i=0;i #include #include "regex.h" +#include "stream.h" namespace YAML { @@ -31,11 +32,6 @@ namespace YAML void Scan(); private: - char GetChar(); - std::string GetChar(int n); - void Eat(int n = 1); - void EatLineBreak(); - bool IsWhitespaceToBeEaten(char ch); bool IsDocumentStart(); bool IsDocumentEnd(); @@ -44,9 +40,6 @@ namespace YAML bool IsValue(); bool IsPlainScalar(); - void GetBlockIndentation(int& indent, std::string& breaks); - std::string ScanScalar(RegEx end, bool eatEnd, int indent, char escape, bool fold, bool eatLeadingWhitespace, bool trimTrailingSpaces, int chomp); - struct SimpleKey { SimpleKey(int pos_, int line_, int column_, int flowLevel_); @@ -63,8 +56,7 @@ namespace YAML private: // the stream - std::istream& INPUT; - int m_line, m_column; + Stream INPUT; // the output (tokens) std::queue m_tokens; diff --git a/scanscalar.cpp b/scanscalar.cpp index 1a323ce..a5ef686 100644 --- a/scanscalar.cpp +++ b/scanscalar.cpp @@ -142,7 +142,7 @@ namespace YAML if(m_simpleKeyAllowed) InsertSimpleKey(); - pToken->value = ScanScalar(end, false, indent, 0, true, true, true, 0); + pToken->value = ScanScalar(INPUT, end, false, indent, 0, true, true, true, 0); m_simpleKeyAllowed = false; if(true/*info.leadingBlanks*/) @@ -221,7 +221,7 @@ namespace YAML //} // eat single or double quote - char quote = GetChar(); + char quote = INPUT.GetChar(); pToken->single = (quote == '\''); RegEx end = (pToken->single ? RegEx(quote) && !Exp::EscSingleQuote : RegEx(quote)); @@ -231,7 +231,7 @@ namespace YAML if(m_simpleKeyAllowed) InsertSimpleKey(); - pToken->value = ScanScalar(end, true, 0, escape, true, true, false, 0); + pToken->value = ScanScalar(INPUT, end, true, 0, escape, true, true, false, 0); m_simpleKeyAllowed = false; return pToken; @@ -243,39 +243,39 @@ namespace YAML WhitespaceInfo info; // eat block indicator ('|' or '>') - char indicator = GetChar(); + char indicator = INPUT.GetChar(); info.fold = (indicator == Keys::FoldedScalar); // eat chomping/indentation indicators int n = Exp::Chomp.Match(INPUT); for(int i=0;i= 0) indent += m_indents.top(); - GetBlockIndentation(indent, info.trailingBreaks); + GetBlockIndentation(INPUT, indent, info.trailingBreaks, m_indents.top()); bool eatLeadingWhitespace = false; - pToken->value = ScanScalar(RegEx(), false, indent, 0, info.fold, eatLeadingWhitespace, false, info.chomp); + pToken->value = ScanScalar(INPUT, RegEx(), false, indent, 0, info.fold, eatLeadingWhitespace, false, info.chomp); // simple keys always ok after block scalars (since we're gonna start a new line anyways) m_simpleKeyAllowed = true; @@ -286,20 +286,20 @@ namespace YAML // . Helper to scanning a block scalar. // . Eats leading *indentation* zeros (i.e., those that come before 'indent'), // and updates 'indent' (if it hasn't been set yet). - void Scanner::GetBlockIndentation(int& indent, std::string& breaks) + void GetBlockIndentation(Stream& INPUT, int& indent, std::string& breaks, int topIndent) { int maxIndent = 0; while(1) { // eat as many indentation spaces as we can - while((indent == 0 || m_column < indent) && INPUT.peek() == ' ') - Eat(1); + while((indent == 0 || INPUT.column < indent) && INPUT.peek() == ' ') + INPUT.Eat(1); - if(m_column > maxIndent) - maxIndent = m_column; + if(INPUT.column > maxIndent) + maxIndent = INPUT.column; // do we need more indentation, but we've got a tab? - if((indent == 0 || m_column < indent) && INPUT.peek() == '\t') + if((indent == 0 || INPUT.column < indent) && INPUT.peek() == '\t') throw IllegalTabInScalar(); // TODO: are literal scalar lines allowed to have tabs here? // is this a non-empty line? @@ -308,21 +308,21 @@ namespace YAML // otherwise, eat the line break and move on int n = Exp::Break.Match(INPUT); - breaks += GetChar(n); + breaks += INPUT.GetChar(n); } // finally, set the indentation if(indent == 0) { indent = maxIndent; - if(indent < m_indents.top() + 1) - indent = m_indents.top() + 1; + if(indent < topIndent + 1) + indent = topIndent + 1; if(indent < 1) indent = 1; } } // ScanScalar - std::string Scanner::ScanScalar(RegEx end, bool eatEnd, int indent, char escape, bool fold, bool eatLeadingWhitespace, bool trimTrailingSpaces, int chomp) + std::string ScanScalar(Stream& INPUT, RegEx end, bool eatEnd, int indent, char escape, bool fold, bool eatLeadingWhitespace, bool trimTrailingSpaces, int chomp) { bool emptyLine = false, moreIndented = false; std::string scalar; @@ -337,20 +337,18 @@ namespace YAML // escaped newline? (only if we're escaping on slash) if(escape == '\\' && Exp::EscBreak.Matches(INPUT)) { int n = Exp::EscBreak.Match(INPUT); - Eat(n); + INPUT.Eat(n); continue; } // escape this? if(INPUT.peek() == escape) { - int length = 0; - scalar += Exp::Escape(INPUT, length); - m_column += length; + scalar += Exp::Escape(INPUT); continue; } // otherwise, just add the damn character - scalar += GetChar(); + scalar += INPUT.GetChar(); } // eof? if we're looking to eat something, then we throw @@ -364,26 +362,26 @@ namespace YAML int n = end.Match(INPUT); if(n >= 0) { if(eatEnd) - Eat(n); + INPUT.Eat(n); break; } // ******************************** // Phase #2: eat line ending n = Exp::Break.Match(INPUT); - Eat(n); + INPUT.Eat(n); // ******************************** // Phase #3: scan initial spaces // first the required indentation - while(INPUT.peek() == ' ' && m_column < indent) - Eat(1); + while(INPUT.peek() == ' ' && INPUT.column < indent) + INPUT.Eat(1); // and then the rest of the whitespace if(eatLeadingWhitespace) { while(Exp::Blank.Matches(INPUT)) - Eat(1); + INPUT.Eat(1); } // was this an empty line? @@ -399,7 +397,7 @@ namespace YAML moreIndented = nextMoreIndented; // are we done via indentation? - if(!emptyLine && m_column < indent) + if(!emptyLine && INPUT.column < indent) break; } diff --git a/scanscalar.h b/scanscalar.h index d63831b..f1d4fca 100644 --- a/scanscalar.h +++ b/scanscalar.h @@ -1,9 +1,14 @@ #pragma once #include +#include "regex.h" +#include "stream.h" namespace YAML { + void GetBlockIndentation(Stream& INPUT, int& indent, std::string& breaks, int topIndent); + std::string ScanScalar(Stream& INPUT, RegEx end, bool eatEnd, int indent, char escape, bool fold, bool eatLeadingWhitespace, bool trimTrailingSpaces, int chomp); + struct WhitespaceInfo { WhitespaceInfo(); diff --git a/scantoken.cpp b/scantoken.cpp index 5f9bcc0..9197f28 100644 --- a/scantoken.cpp +++ b/scantoken.cpp @@ -22,8 +22,8 @@ namespace YAML template <> StreamEndToken *Scanner::ScanToken(StreamEndToken *pToken) { // force newline - if(m_column > 0) - m_column = 0; + if(INPUT.column > 0) + INPUT.column = 0; PopIndentTo(-1); ValidateAllSimpleKeys(); @@ -37,12 +37,12 @@ namespace YAML // DocumentStartToken template <> DocumentStartToken *Scanner::ScanToken(DocumentStartToken *pToken) { - PopIndentTo(m_column); + PopIndentTo(INPUT.column); ValidateAllSimpleKeys(); m_simpleKeyAllowed = false; // eat - Eat(3); + INPUT.Eat(3); return pToken; } @@ -54,7 +54,7 @@ namespace YAML m_simpleKeyAllowed = false; // eat - Eat(3); + INPUT.Eat(3); return pToken; } @@ -67,7 +67,7 @@ namespace YAML m_simpleKeyAllowed = true; // eat - Eat(1); + INPUT.Eat(1); return pToken; } @@ -80,7 +80,7 @@ namespace YAML m_simpleKeyAllowed = true; // eat - Eat(1); + INPUT.Eat(1); return pToken; } @@ -94,7 +94,7 @@ namespace YAML m_simpleKeyAllowed = false; // eat - Eat(1); + INPUT.Eat(1); return pToken; } @@ -108,7 +108,7 @@ namespace YAML m_simpleKeyAllowed = false; // eat - Eat(1); + INPUT.Eat(1); return pToken; } @@ -118,7 +118,7 @@ namespace YAML m_simpleKeyAllowed = true; // eat - Eat(1); + INPUT.Eat(1); return pToken; } @@ -133,11 +133,11 @@ namespace YAML if(!m_simpleKeyAllowed) throw IllegalBlockEntry(); - PushIndentTo(m_column, true); + PushIndentTo(INPUT.column, true); m_simpleKeyAllowed = true; // eat - Eat(1); + INPUT.Eat(1); return pToken; } @@ -149,7 +149,7 @@ namespace YAML if(!m_simpleKeyAllowed) throw IllegalMapKey(); - PushIndentTo(m_column, false); + PushIndentTo(INPUT.column, false); } // can only put a simple key here if we're in block context @@ -159,7 +159,7 @@ namespace YAML m_simpleKeyAllowed = false; // eat - Eat(1); + INPUT.Eat(1); return pToken; } @@ -176,7 +176,7 @@ namespace YAML if(!m_simpleKeyAllowed) throw IllegalMapValue(); - PushIndentTo(m_column, false); + PushIndentTo(INPUT.column, false); } // can only put a simple key here if we're in block context @@ -187,7 +187,7 @@ namespace YAML } // eat - Eat(1); + INPUT.Eat(1); return pToken; } @@ -200,13 +200,13 @@ namespace YAML m_simpleKeyAllowed = false; // eat the indicator - char indicator = GetChar(); + char indicator = INPUT.GetChar(); pToken->alias = (indicator == Keys::Alias); // now eat the content std::string tag; while(Exp::AlphaNumeric.Matches(INPUT)) - tag += GetChar(); + tag += INPUT.GetChar(); // we need to have read SOMETHING! if(tag.empty()) diff --git a/simplekey.cpp b/simplekey.cpp index cf90bd2..0f306e8 100644 --- a/simplekey.cpp +++ b/simplekey.cpp @@ -34,10 +34,10 @@ namespace YAML // and saves it on a stack. void Scanner::InsertSimpleKey() { - SimpleKey key(INPUT.tellg(), m_line, m_column, m_flowLevel); + SimpleKey key(INPUT.pos(), INPUT.line, INPUT.column, m_flowLevel); // first add a map start, if necessary - key.pMapStart = PushIndentTo(m_column, false); + key.pMapStart = PushIndentTo(INPUT.column, false); if(key.pMapStart) key.pMapStart->isValid = false; // else @@ -79,7 +79,7 @@ namespace YAML isValid = false; // also needs to be less than 1024 characters and inline - if(m_line != key.line || (int) INPUT.tellg() - key.pos > 1024) + if(INPUT.line != key.line || INPUT.pos() - key.pos > 1024) isValid = false; // invalidate key diff --git a/stream.cpp b/stream.cpp new file mode 100644 index 0000000..b4a5050 --- /dev/null +++ b/stream.cpp @@ -0,0 +1,43 @@ +#include "stream.h" + +namespace YAML +{ + // GetChar + // . Extracts a character from the stream and updates our position + char Stream::GetChar() + { + char ch = input.get(); + column++; + if(ch == '\n') { + column = 0; + line++; + } + return ch; + } + + // GetChar + // . Extracts 'n' characters from the stream and updates our position + std::string Stream::GetChar(int n) + { + std::string ret; + for(int i=0;i +#include + +namespace YAML +{ + struct Stream + { + Stream(std::istream& input_): input(input_), line(0), column(0) {} + + char peek() { return input.peek(); } + int pos() const { return input.tellg(); } + operator std::istream& () { return input; } + operator bool() { return input.good(); } + bool operator !() { return !input; } + + char GetChar(); + std::string GetChar(int n); + void Eat(int n = 1); + void EatLineBreak(); + + std::istream& input; + int line, column; + }; +} diff --git a/test.yaml b/test.yaml index ee5d76e..276943a 100644 --- a/test.yaml +++ b/test.yaml @@ -1,4 +1,12 @@ --- -- "quoted scalar that contains ---- - the document start!" \ No newline at end of file +- "quoted scalar\twith a tab\nand a newline" +- 'This is Jesse''s single quote!' +- | + here's a literal: + #include + + int main() + { + std::cout << "Hello World!\n"; + return 0; + } \ No newline at end of file diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index d68609b..a0ae76d 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -217,6 +217,10 @@ RelativePath=".\simplekey.cpp" > + + + + From 4de9cb48a55f737ac3962309f13b651c8b7cd607 Mon Sep 17 00:00:00 2001 From: beder Date: Sun, 29 Jun 2008 17:39:33 +0000 Subject: [PATCH 025/295] Moved scalar scanning-related parameters to a struct. Renamed the valid/possible tokens to a single variable status with enums valid, invalid, and unverified. --- regex.cpp | 15 ++++++++++++ regex.h | 2 ++ scanner.cpp | 11 ++++----- scanner.h | 4 ++-- scanscalar.cpp | 65 ++++++++++++++++++++++++++++++++------------------ scanscalar.h | 18 +++++++++++++- scantoken.cpp | 6 ++--- simplekey.cpp | 23 +++++++++--------- test.yaml | 4 +++- token.h | 6 +++-- 10 files changed, 104 insertions(+), 50 deletions(-) diff --git a/regex.cpp b/regex.cpp index 040ccb9..1da6289 100644 --- a/regex.cpp +++ b/regex.cpp @@ -45,6 +45,21 @@ namespace YAML delete m_pOp; } + RegEx& RegEx::operator = (const RegEx& rhs) + { + delete m_pOp; + m_pOp = 0; + + m_op = rhs.m_op; + m_a = rhs.m_a; + m_z = rhs.m_z; + m_params = rhs.m_params; + + SetOp(); + + return *this; + } + void RegEx::SetOp() { delete m_pOp; diff --git a/regex.h b/regex.h index 7298418..b5429c7 100644 --- a/regex.h +++ b/regex.h @@ -60,6 +60,8 @@ namespace YAML RegEx(const RegEx& rhs); ~RegEx(); + RegEx& operator = (const RegEx& rhs); + bool Matches(char ch) const; bool Matches(const std::string& str) const; bool Matches(std::istream& in) const; diff --git a/scanner.cpp b/scanner.cpp index ace4995..5e83907 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -123,7 +123,7 @@ namespace YAML ScanToNextToken(); // check the latest simple key - ValidateSimpleKey(); + VerifySimpleKey(); // maybe need to end some blocks PopIndentTo(INPUT.column); @@ -213,7 +213,7 @@ namespace YAML INPUT.EatLineBreak(); // oh yeah, and let's get rid of that simple key - ValidateSimpleKey(); + VerifySimpleKey(); // new line - we may be able to accept a simple key now if(m_flowLevel == 0) @@ -272,16 +272,15 @@ namespace YAML if(!m_tokens.empty()) pToken = m_tokens.front(); - // ... that's possible // (here's where we clean up the impossible tokens) - if(pToken && !pToken->isPossible) { + if(pToken && pToken->status == TS_INVALID) { m_tokens.pop(); delete pToken; continue; } - // and valid - if(pToken && !pToken->isValid) + // on unverified tokens, we just have to wait + if(pToken && pToken->status == TS_UNVERIFIED) pToken = 0; // then that's what we want diff --git a/scanner.h b/scanner.h index ebe8e7f..ec6173b 100644 --- a/scanner.h +++ b/scanner.h @@ -26,8 +26,8 @@ namespace YAML void PopIndentTo(int column); void InsertSimpleKey(); - bool ValidateSimpleKey(); - void ValidateAllSimpleKeys(); + bool VerifySimpleKey(); + void VerifyAllSimpleKeys(); void Scan(); diff --git a/scanscalar.cpp b/scanscalar.cpp index a5ef686..480480a 100644 --- a/scanscalar.cpp +++ b/scanscalar.cpp @@ -135,14 +135,20 @@ namespace YAML // scalar += info.Join(); //} - RegEx end = (m_flowLevel > 0 ? Exp::EndScalarInFlow : Exp::EndScalar) || (RegEx(' ') + Exp::Comment); - int indent = (m_flowLevel > 0 ? 0 : m_indents.top() + 1); + ScanScalarInfo info; + info.end = (m_flowLevel > 0 ? Exp::EndScalarInFlow : Exp::EndScalar) || (RegEx(' ') + Exp::Comment); + info.eatEnd = false; + info.indent = (m_flowLevel > 0 ? 0 : m_indents.top() + 1); + info.fold = true; + info.eatLeadingWhitespace = true; + info.trimTrailingSpaces = true; + info.chomp = CLIP; // insert a potential simple key if(m_simpleKeyAllowed) InsertSimpleKey(); - pToken->value = ScanScalar(INPUT, end, false, indent, 0, true, true, true, 0); + pToken->value = ScanScalar(INPUT, info); m_simpleKeyAllowed = false; if(true/*info.leadingBlanks*/) @@ -224,14 +230,21 @@ namespace YAML char quote = INPUT.GetChar(); pToken->single = (quote == '\''); - RegEx end = (pToken->single ? RegEx(quote) && !Exp::EscSingleQuote : RegEx(quote)); - char escape = (pToken->single ? '\'' : '\\'); + ScanScalarInfo info; + info.end = (pToken->single ? RegEx(quote) && !Exp::EscSingleQuote : RegEx(quote)); + info.eatEnd = true; + info.escape = (pToken->single ? '\'' : '\\'); + info.indent = 0; + info.fold = true; + info.eatLeadingWhitespace = true; + info.trimTrailingSpaces = false; + info.chomp = CLIP; // insert a potential simple key if(m_simpleKeyAllowed) InsertSimpleKey(); - pToken->value = ScanScalar(INPUT, end, true, 0, escape, true, true, false, 0); + pToken->value = ScanScalar(INPUT, info); m_simpleKeyAllowed = false; return pToken; @@ -274,8 +287,14 @@ namespace YAML GetBlockIndentation(INPUT, indent, info.trailingBreaks, m_indents.top()); - bool eatLeadingWhitespace = false; - pToken->value = ScanScalar(INPUT, RegEx(), false, indent, 0, info.fold, eatLeadingWhitespace, false, info.chomp); + ScanScalarInfo sinfo; + sinfo.indent = indent; + sinfo.fold = info.fold; + sinfo.eatLeadingWhitespace = false; + sinfo.trimTrailingSpaces = false; + sinfo.chomp = (CHOMP) info.chomp; + + pToken->value = ScanScalar(INPUT, sinfo); // simple keys always ok after block scalars (since we're gonna start a new line anyways) m_simpleKeyAllowed = true; @@ -322,7 +341,7 @@ namespace YAML } // ScanScalar - std::string ScanScalar(Stream& INPUT, RegEx end, bool eatEnd, int indent, char escape, bool fold, bool eatLeadingWhitespace, bool trimTrailingSpaces, int chomp) + std::string ScanScalar(Stream& INPUT, ScanScalarInfo info) { bool emptyLine = false, moreIndented = false; std::string scalar; @@ -330,19 +349,19 @@ namespace YAML while(INPUT) { // ******************************** // Phase #1: scan until line ending - while(!end.Matches(INPUT) && !Exp::Break.Matches(INPUT)) { + while(!info.end.Matches(INPUT) && !Exp::Break.Matches(INPUT)) { if(INPUT.peek() == EOF) break; // escaped newline? (only if we're escaping on slash) - if(escape == '\\' && Exp::EscBreak.Matches(INPUT)) { + if(info.escape == '\\' && Exp::EscBreak.Matches(INPUT)) { int n = Exp::EscBreak.Match(INPUT); INPUT.Eat(n); continue; } // escape this? - if(INPUT.peek() == escape) { + if(INPUT.peek() == info.escape) { scalar += Exp::Escape(INPUT); continue; } @@ -353,15 +372,15 @@ namespace YAML // eof? if we're looking to eat something, then we throw if(INPUT.peek() == EOF) { - if(eatEnd) + if(info.eatEnd) throw EOFInQuote(); break; } // are we done via character match? - int n = end.Match(INPUT); + int n = info.end.Match(INPUT); if(n >= 0) { - if(eatEnd) + if(info.eatEnd) INPUT.Eat(n); break; } @@ -375,11 +394,11 @@ namespace YAML // Phase #3: scan initial spaces // first the required indentation - while(INPUT.peek() == ' ' && INPUT.column < indent) + while(INPUT.peek() == ' ' && INPUT.column < info.indent) INPUT.Eat(1); // and then the rest of the whitespace - if(eatLeadingWhitespace) { + if(info.eatLeadingWhitespace) { while(Exp::Blank.Matches(INPUT)) INPUT.Eat(1); } @@ -388,7 +407,7 @@ namespace YAML bool nextEmptyLine = Exp::Break.Matches(INPUT); bool nextMoreIndented = (INPUT.peek() == ' '); - if(fold && !emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented) + if(info.fold && !emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented) scalar += " "; else scalar += "\n"; @@ -397,22 +416,22 @@ namespace YAML moreIndented = nextMoreIndented; // are we done via indentation? - if(!emptyLine && INPUT.column < indent) + if(!emptyLine && INPUT.column < info.indent) break; } // post-processing - if(trimTrailingSpaces) { + if(info.trimTrailingSpaces) { unsigned pos = scalar.find_last_not_of(' '); if(pos < scalar.size()) scalar.erase(pos + 1); } - if(chomp <= 0) { + if(info.chomp <= 0) { unsigned pos = scalar.find_last_not_of('\n'); - if(chomp == 0 && pos + 1 < scalar.size()) + if(info.chomp == 0 && pos + 1 < scalar.size()) scalar.erase(pos + 2); - else if(chomp == -1 && pos < scalar.size()) + else if(info.chomp == -1 && pos < scalar.size()) scalar.erase(pos + 1); } diff --git a/scanscalar.h b/scanscalar.h index f1d4fca..f4987a1 100644 --- a/scanscalar.h +++ b/scanscalar.h @@ -6,8 +6,24 @@ namespace YAML { + enum CHOMP { STRIP = -1, CLIP, KEEP }; + + struct ScanScalarInfo { + ScanScalarInfo(): eatEnd(false), indent(0), eatLeadingWhitespace(0), escape(0), fold(false), trimTrailingSpaces(0), chomp(CLIP) {} + + RegEx end; // what condition ends this scalar? + bool eatEnd; // should we eat that condition when we see it? + int indent; // what level of indentation should be eaten and ignored? + bool eatLeadingWhitespace; // should we continue eating this delicious indentation after 'indent' spaces? + char escape; // what character do we escape on (i.e., slash or single quote) (0 for none) + bool fold; // do we fold line ends? + bool trimTrailingSpaces; // do we remove all trailing spaces (at the very end) + CHOMP chomp; // do we strip, clip, or keep trailing newlines (at the very end) + // Note: strip means kill all, clip means keep at most one, keep means keep all + }; + void GetBlockIndentation(Stream& INPUT, int& indent, std::string& breaks, int topIndent); - std::string ScanScalar(Stream& INPUT, RegEx end, bool eatEnd, int indent, char escape, bool fold, bool eatLeadingWhitespace, bool trimTrailingSpaces, int chomp); + std::string ScanScalar(Stream& INPUT, ScanScalarInfo info); struct WhitespaceInfo { WhitespaceInfo(); diff --git a/scantoken.cpp b/scantoken.cpp index 9197f28..6eefa8a 100644 --- a/scantoken.cpp +++ b/scantoken.cpp @@ -26,7 +26,7 @@ namespace YAML INPUT.column = 0; PopIndentTo(-1); - ValidateAllSimpleKeys(); + VerifyAllSimpleKeys(); m_simpleKeyAllowed = false; m_endedStream = true; @@ -38,7 +38,7 @@ namespace YAML template <> DocumentStartToken *Scanner::ScanToken(DocumentStartToken *pToken) { PopIndentTo(INPUT.column); - ValidateAllSimpleKeys(); + VerifyAllSimpleKeys(); m_simpleKeyAllowed = false; // eat @@ -50,7 +50,7 @@ namespace YAML template <> DocumentEndToken *Scanner::ScanToken(DocumentEndToken *pToken) { PopIndentTo(-1); - ValidateAllSimpleKeys(); + VerifyAllSimpleKeys(); m_simpleKeyAllowed = false; // eat diff --git a/simplekey.cpp b/simplekey.cpp index 0f306e8..aa5d8b3 100644 --- a/simplekey.cpp +++ b/simplekey.cpp @@ -13,9 +13,9 @@ namespace YAML void Scanner::SimpleKey::Validate() { if(pMapStart) - pMapStart->isValid = true; + pMapStart->status = TS_VALID; if(pKey) - pKey->isValid = true; + pKey->status = TS_VALID; } void Scanner::SimpleKey::Invalidate() @@ -24,9 +24,9 @@ namespace YAML throw RequiredSimpleKeyNotFound(); if(pMapStart) - pMapStart->isPossible = false; + pMapStart->status = TS_INVALID; if(pKey) - pKey->isPossible = false; + pKey->status = TS_INVALID; } // InsertSimpleKey @@ -39,23 +39,22 @@ namespace YAML // first add a map start, if necessary key.pMapStart = PushIndentTo(INPUT.column, false); if(key.pMapStart) - key.pMapStart->isValid = false; + key.pMapStart->status = TS_UNVERIFIED; // else // key.required = true; // TODO: is this correct? - // then add the (now invalid) key + // then add the (now unverified) key key.pKey = new KeyToken; - key.pKey->isValid = false; - + key.pKey->status = TS_UNVERIFIED; m_tokens.push(key.pKey); m_simpleKeys.push(key); } - // ValidateSimpleKey + // VerifySimpleKey // . Determines whether the latest simple key to be added is valid, // and if so, makes it valid. - bool Scanner::ValidateSimpleKey() + bool Scanner::VerifySimpleKey() { m_isLastKeyValid = false; if(m_simpleKeys.empty()) @@ -99,9 +98,9 @@ namespace YAML return isValid; } - void Scanner::ValidateAllSimpleKeys() + void Scanner::VerifyAllSimpleKeys() { while(!m_simpleKeys.empty()) - ValidateSimpleKey(); + VerifySimpleKey(); } } diff --git a/test.yaml b/test.yaml index 276943a..a7221f0 100644 --- a/test.yaml +++ b/test.yaml @@ -9,4 +9,6 @@ { std::cout << "Hello World!\n"; return 0; - } \ No newline at end of file + } +- key1: value1 + key2: value2 \ No newline at end of file diff --git a/token.h b/token.h index 8121817..70fd7fd 100644 --- a/token.h +++ b/token.h @@ -4,13 +4,15 @@ namespace YAML { + enum TOKEN_STATUS { TS_VALID, TS_INVALID, TS_UNVERIFIED }; + struct Token { - Token(): isValid(true), isPossible(true) {} + Token(): status(TS_VALID) {} virtual ~Token() {} virtual void Write(std::ostream& out) const {} friend std::ostream& operator << (std::ostream& out, const Token& token) { token.Write(out); return out; } - bool isValid, isPossible; + TOKEN_STATUS status; }; struct StreamStartToken: public Token {}; From 67250833b8c45ede0e4d682d7fe97435ad061a8b Mon Sep 17 00:00:00 2001 From: beder Date: Mon, 30 Jun 2008 01:31:23 +0000 Subject: [PATCH 026/295] Mostly finished refactoring the scalar scanning. --- exceptions.h | 6 +- exp.h | 1 + scanner.h | 7 +- scanscalar.cpp | 499 ++++++++++++++++--------------------------------- scanscalar.h | 28 ++- test.yaml | 29 +-- 6 files changed, 192 insertions(+), 378 deletions(-) diff --git a/exceptions.h b/exceptions.h index f8968b7..3c66d85 100644 --- a/exceptions.h +++ b/exceptions.h @@ -11,10 +11,10 @@ namespace YAML class IllegalMapKey: public Exception {}; class IllegalMapValue: public Exception {}; class IllegalScalar: public Exception {}; - class IllegalTabInScalar: public Exception {}; + class IllegalTabInIndentation: public Exception {}; class IllegalFlowEnd: public Exception {}; - class DocIndicatorInQuote: public Exception {}; - class EOFInQuote: public Exception {}; + class IllegalDocIndicator: public Exception {}; + class IllegalEOF: public Exception {}; class RequiredSimpleKeyNotFound: public Exception {}; class ZeroIndentationInBlockScalar: public Exception {}; class UnexpectedCharacterInBlockScalar: public Exception {}; diff --git a/exp.h b/exp.h index 85d9520..ea1804b 100644 --- a/exp.h +++ b/exp.h @@ -25,6 +25,7 @@ namespace YAML const RegEx DocStart = RegEx("---") + (BlankOrBreak || RegEx(EOF) || RegEx()); const RegEx DocEnd = RegEx("...") + (BlankOrBreak || RegEx(EOF) || RegEx()); + const RegEx DocIndicator = DocStart || DocEnd; const RegEx BlockEntry = RegEx('-') + (BlankOrBreak || RegEx(EOF)); const RegEx Key = RegEx('?'), KeyInFlow = RegEx('?') + BlankOrBreak; diff --git a/scanner.h b/scanner.h index ec6173b..fd5ad1a 100644 --- a/scanner.h +++ b/scanner.h @@ -19,19 +19,20 @@ namespace YAML ~Scanner(); Token *GetNextToken(); + void Scan(); + private: + // scanning void ScanNextToken(); void ScanToNextToken(); Token *PushIndentTo(int column, bool sequence); void PopIndentTo(int column); + // checking input void InsertSimpleKey(); bool VerifySimpleKey(); void VerifyAllSimpleKeys(); - void Scan(); - - private: bool IsWhitespaceToBeEaten(char ch); bool IsDocumentStart(); bool IsDocumentEnd(); diff --git a/scanscalar.cpp b/scanscalar.cpp index 480480a..b3577f5 100644 --- a/scanscalar.cpp +++ b/scanscalar.cpp @@ -6,345 +6,13 @@ namespace YAML { - ////////////////////////////////////////////////////////// - // WhitespaceInfo - - WhitespaceInfo::WhitespaceInfo(): leadingBlanks(false), fold(true), chomp(0), increment(0) - { - } - - void WhitespaceInfo::SetChompers(char ch) - { - if(ch == '+') - chomp = 1; - else if(ch == '-') - chomp = -1; - else if(Exp::Digit.Matches(ch)) { - increment = ch - '0'; - if(increment == 0) - throw ZeroIndentationInBlockScalar(); - } - } - - void WhitespaceInfo::AddBlank(char ch) - { - if(!leadingBlanks) - whitespace += ch; - } - - void WhitespaceInfo::AddBreak(const std::string& line) - { - // where to store this character? - if(!leadingBlanks) { - leadingBlanks = true; - whitespace = ""; - leadingBreaks += line; - } else - trailingBreaks += line; - } - - std::string WhitespaceInfo::Join(bool lastLine) - { - std::string ret; - - if(leadingBlanks) { - // fold line break? - if(fold && Exp::Break.Matches(leadingBreaks) && trailingBreaks.empty() && !lastLine) - ret = " "; - else if(!lastLine || chomp != -1) - ret = leadingBreaks; - - if(!lastLine || chomp == 1) - ret += trailingBreaks; - - leadingBlanks = false; - leadingBreaks = ""; - trailingBreaks = ""; - } else if(!whitespace.empty()) { - ret = whitespace; - whitespace = ""; - } - - return ret; - } - - // PlainScalarToken - // . We scan these in passes of two steps each: First, grab all non-whitespace - // characters we can, and then grab all whitespace characters we can. - // . This has the benefit of letting us handle leading whitespace (which is chomped) - // and in-line whitespace (which is kept) separately. - template <> PlainScalarToken *Scanner::ScanToken(PlainScalarToken *pToken) - { - //// now eat and store the scalar - //std::string scalar; - //WhitespaceInfo info; - - //while(INPUT) { - // // doc start/end tokens - // if(IsDocumentStart() || IsDocumentEnd()) - // break; - - // // comment - // if(Exp::Comment.Matches(INPUT)) - // break; - - // // first eat non-blanks - // while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) { - // // illegal colon in flow context - // if(m_flowLevel > 0 && Exp::IllegalColonInScalar.Matches(INPUT)) - // throw IllegalScalar(); - - // // characters that might end the scalar - // if(m_flowLevel > 0 && Exp::EndScalarInFlow.Matches(INPUT)) - // break; - // if(m_flowLevel == 0 && Exp::EndScalar.Matches(INPUT)) - // break; - - // // finally, read the character! - // scalar += GetChar(); - // } - - // // did we hit a non-blank character that ended us? - // if(!Exp::BlankOrBreak.Matches(INPUT)) - // break; - - // // now eat blanks - // while(INPUT && Exp::BlankOrBreak.Matches(INPUT)) { - // if(Exp::Blank.Matches(INPUT)) { - // // can't use tabs as indentation! only spaces! - // if(INPUT.peek() == '\t' && info.leadingBlanks && m_column <= m_indents.top()) - // throw IllegalTabInScalar(); - - // info.AddBlank(GetChar()); - // } else { - // // we know it's a line break; see how many characters to read - // int n = Exp::Break.Match(INPUT); - // std::string line = GetChar(n); - // info.AddBreak(line); - - // // and we can't continue a simple key to the next line - // ValidateSimpleKey(); - // } - // } - - // // break if we're below the indentation level - // if(m_flowLevel == 0 && m_column <= m_indents.top()) - // break; - - // // finally join whitespace - // scalar += info.Join(); - //} - - ScanScalarInfo info; - info.end = (m_flowLevel > 0 ? Exp::EndScalarInFlow : Exp::EndScalar) || (RegEx(' ') + Exp::Comment); - info.eatEnd = false; - info.indent = (m_flowLevel > 0 ? 0 : m_indents.top() + 1); - info.fold = true; - info.eatLeadingWhitespace = true; - info.trimTrailingSpaces = true; - info.chomp = CLIP; - - // insert a potential simple key - if(m_simpleKeyAllowed) - InsertSimpleKey(); - - pToken->value = ScanScalar(INPUT, info); - - m_simpleKeyAllowed = false; - if(true/*info.leadingBlanks*/) - m_simpleKeyAllowed = true; - - return pToken; - } - - // QuotedScalarToken - template <> QuotedScalarToken *Scanner::ScanToken(QuotedScalarToken *pToken) - { - //// now eat and store the scalar - //std::string scalar; - //WhitespaceInfo info; - - //while(INPUT) { - // if(IsDocumentStart() || IsDocumentEnd()) - // throw DocIndicatorInQuote(); - - // if(INPUT.peek() == EOF) - // throw EOFInQuote(); - - // // first eat non-blanks - // while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) { - // // escaped single quote? - // if(pToken->single && Exp::EscSingleQuote.Matches(INPUT)) { - // int n = Exp::EscSingleQuote.Match(INPUT); - // scalar += GetChar(n); - // continue; - // } - - // // is the quote ending? - // if(INPUT.peek() == quote) - // break; - - // // escaped newline? - // if(Exp::EscBreak.Matches(INPUT)) - // break; - - // // other escape sequence - // if(INPUT.peek() == '\\') { - // int length = 0; - // scalar += Exp::Escape(INPUT, length); - // m_column += length; - // continue; - // } - - // // and finally, just add the damn character - // scalar += GetChar(); - // } - - // // is the quote ending? - // if(INPUT.peek() == quote) { - // // eat and go - // GetChar(); - // break; - // } - - // // now we eat blanks - // while(Exp::BlankOrBreak.Matches(INPUT)) { - // if(Exp::Blank.Matches(INPUT)) { - // info.AddBlank(GetChar()); - // } else { - // // we know it's a line break; see how many characters to read - // int n = Exp::Break.Match(INPUT); - // std::string line = GetChar(n); - // info.AddBreak(line); - - // // and we can't continue a simple key to the next line - // ValidateSimpleKey(); - // } - // } - - // // and finally join the whitespace - // scalar += info.Join(); - //} - - // eat single or double quote - char quote = INPUT.GetChar(); - pToken->single = (quote == '\''); - - ScanScalarInfo info; - info.end = (pToken->single ? RegEx(quote) && !Exp::EscSingleQuote : RegEx(quote)); - info.eatEnd = true; - info.escape = (pToken->single ? '\'' : '\\'); - info.indent = 0; - info.fold = true; - info.eatLeadingWhitespace = true; - info.trimTrailingSpaces = false; - info.chomp = CLIP; - - // insert a potential simple key - if(m_simpleKeyAllowed) - InsertSimpleKey(); - - pToken->value = ScanScalar(INPUT, info); - m_simpleKeyAllowed = false; - - return pToken; - } - - // BlockScalarToken - template <> BlockScalarToken *Scanner::ScanToken(BlockScalarToken *pToken) - { - WhitespaceInfo info; - - // eat block indicator ('|' or '>') - char indicator = INPUT.GetChar(); - info.fold = (indicator == Keys::FoldedScalar); - - // eat chomping/indentation indicators - int n = Exp::Chomp.Match(INPUT); - for(int i=0;i= 0) - indent += m_indents.top(); - - GetBlockIndentation(INPUT, indent, info.trailingBreaks, m_indents.top()); - - ScanScalarInfo sinfo; - sinfo.indent = indent; - sinfo.fold = info.fold; - sinfo.eatLeadingWhitespace = false; - sinfo.trimTrailingSpaces = false; - sinfo.chomp = (CHOMP) info.chomp; - - pToken->value = ScanScalar(INPUT, sinfo); - - // simple keys always ok after block scalars (since we're gonna start a new line anyways) - m_simpleKeyAllowed = true; - return pToken; - } - - // GetBlockIndentation - // . Helper to scanning a block scalar. - // . Eats leading *indentation* zeros (i.e., those that come before 'indent'), - // and updates 'indent' (if it hasn't been set yet). - void GetBlockIndentation(Stream& INPUT, int& indent, std::string& breaks, int topIndent) - { - int maxIndent = 0; - - while(1) { - // eat as many indentation spaces as we can - while((indent == 0 || INPUT.column < indent) && INPUT.peek() == ' ') - INPUT.Eat(1); - - if(INPUT.column > maxIndent) - maxIndent = INPUT.column; - - // do we need more indentation, but we've got a tab? - if((indent == 0 || INPUT.column < indent) && INPUT.peek() == '\t') - throw IllegalTabInScalar(); // TODO: are literal scalar lines allowed to have tabs here? - - // is this a non-empty line? - if(!Exp::Break.Matches(INPUT)) - break; - - // otherwise, eat the line break and move on - int n = Exp::Break.Match(INPUT); - breaks += INPUT.GetChar(n); - } - - // finally, set the indentation - if(indent == 0) { - indent = maxIndent; - if(indent < topIndent + 1) - indent = topIndent + 1; - if(indent < 1) - indent = 1; - } - } - // ScanScalar - std::string ScanScalar(Stream& INPUT, ScanScalarInfo info) + std::string ScanScalar(Stream& INPUT, ScanScalarInfo& info) { + bool foundNonEmptyLine = false; bool emptyLine = false, moreIndented = false; std::string scalar; + info.leadingSpaces = false; while(INPUT) { // ******************************** @@ -353,6 +21,16 @@ namespace YAML if(INPUT.peek() == EOF) break; + // document indicator? + if(INPUT.column == 0 && Exp::DocIndicator.Matches(INPUT)) { + if(info.onDocIndicator == BREAK) + break; + else if(info.onDocIndicator == THROW) + throw IllegalDocIndicator(); + } + + foundNonEmptyLine = true; + // escaped newline? (only if we're escaping on slash) if(info.escape == '\\' && Exp::EscBreak.Matches(INPUT)) { int n = Exp::EscBreak.Match(INPUT); @@ -373,10 +51,14 @@ namespace YAML // eof? if we're looking to eat something, then we throw if(INPUT.peek() == EOF) { if(info.eatEnd) - throw EOFInQuote(); + throw IllegalEOF(); break; } + // doc indicator? + if(info.onDocIndicator == BREAK && INPUT.column == 0 && Exp::DocIndicator.Matches(INPUT)) + break; + // are we done via character match? int n = info.end.Match(INPUT); if(n >= 0) { @@ -394,30 +76,44 @@ namespace YAML // Phase #3: scan initial spaces // first the required indentation - while(INPUT.peek() == ' ' && INPUT.column < info.indent) + while(INPUT.peek() == ' ' && (INPUT.column < info.indent || (info.detectIndent && !foundNonEmptyLine))) INPUT.Eat(1); + // update indent if we're auto-detecting + if(info.detectIndent && !foundNonEmptyLine) + info.indent = std::max(info.indent, INPUT.column); + // and then the rest of the whitespace - if(info.eatLeadingWhitespace) { - while(Exp::Blank.Matches(INPUT)) - INPUT.Eat(1); + while(Exp::Blank.Matches(INPUT)) { + // we check for tabs that masquerade as indentation + if(INPUT.peek() == '\t'&& INPUT.column < info.indent && info.onTabInIndentation == THROW) + throw IllegalTabInIndentation(); + + if(!info.eatLeadingWhitespace) + break; + + INPUT.Eat(1); } // was this an empty line? bool nextEmptyLine = Exp::Break.Matches(INPUT); bool nextMoreIndented = (INPUT.peek() == ' '); + // TODO: for block scalars, we always start with a newline, so we should fold OR keep that + if(info.fold && !emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented) scalar += " "; else - scalar += "\n"; + scalar += "\n"; emptyLine = nextEmptyLine; moreIndented = nextMoreIndented; // are we done via indentation? - if(!emptyLine && INPUT.column < info.indent) + if(!emptyLine && INPUT.column < info.indent) { + info.leadingSpaces = true; break; + } } // post-processing @@ -437,4 +133,123 @@ namespace YAML return scalar; } + + // PlainScalarToken + template <> PlainScalarToken *Scanner::ScanToken(PlainScalarToken *pToken) + { + // set up the scanning parameters + ScanScalarInfo info; + info.end = (m_flowLevel > 0 ? Exp::EndScalarInFlow : Exp::EndScalar) || (RegEx(' ') + Exp::Comment); + info.eatEnd = false; + info.indent = (m_flowLevel > 0 ? 0 : m_indents.top() + 1); + info.fold = true; + info.eatLeadingWhitespace = true; + info.trimTrailingSpaces = true; + info.chomp = CLIP; + info.onDocIndicator = BREAK; + info.onTabInIndentation = THROW; + + // insert a potential simple key + if(m_simpleKeyAllowed) + InsertSimpleKey(); + + pToken->value = ScanScalar(INPUT, info); + + // can have a simple key only if we ended the scalar by starting a new line + m_simpleKeyAllowed = info.leadingSpaces; + + // finally, we can't have any colons in a scalar, so if we ended on a colon, there + // had better be a break after it + if(Exp::IllegalColonInScalar.Matches(INPUT)) + throw IllegalScalar(); + + return pToken; + } + + // QuotedScalarToken + template <> QuotedScalarToken *Scanner::ScanToken(QuotedScalarToken *pToken) + { + // eat single or double quote + char quote = INPUT.GetChar(); + pToken->single = (quote == '\''); + + // setup the scanning parameters + ScanScalarInfo info; + info.end = (pToken->single ? RegEx(quote) && !Exp::EscSingleQuote : RegEx(quote)); + info.eatEnd = true; + info.escape = (pToken->single ? '\'' : '\\'); + info.indent = 0; + info.fold = true; + info.eatLeadingWhitespace = true; + info.trimTrailingSpaces = false; + info.chomp = CLIP; + info.onDocIndicator = THROW; + + // insert a potential simple key + if(m_simpleKeyAllowed) + InsertSimpleKey(); + + pToken->value = ScanScalar(INPUT, info); + m_simpleKeyAllowed = false; + + return pToken; + } + + // BlockScalarToken + // . These need a little extra processing beforehand. + // . We need to scan the line where the indicator is (this doesn't count as part of the scalar), + // and then we need to figure out what level of indentation we'll be using. + template <> BlockScalarToken *Scanner::ScanToken(BlockScalarToken *pToken) + { + ScanScalarInfo info; + info.indent = 1; + info.detectIndent = true; + + // eat block indicator ('|' or '>') + char indicator = INPUT.GetChar(); + info.fold = (indicator == Keys::FoldedScalar); + + // eat chomping/indentation indicators + int n = Exp::Chomp.Match(INPUT); + for(int i=0;i= 0) + info.indent += m_indents.top(); + + info.eatLeadingWhitespace = false; + info.trimTrailingSpaces = false; + info.onTabInIndentation = THROW; + + pToken->value = ScanScalar(INPUT, info); + + // simple keys always ok after block scalars (since we're gonna start a new line anyways) + m_simpleKeyAllowed = true; + return pToken; + } } diff --git a/scanscalar.h b/scanscalar.h index f4987a1..c3d0030 100644 --- a/scanscalar.h +++ b/scanscalar.h @@ -7,35 +7,29 @@ namespace YAML { enum CHOMP { STRIP = -1, CLIP, KEEP }; + enum ACTION { NONE, BREAK, THROW }; struct ScanScalarInfo { - ScanScalarInfo(): eatEnd(false), indent(0), eatLeadingWhitespace(0), escape(0), fold(false), trimTrailingSpaces(0), chomp(CLIP) {} + ScanScalarInfo(): eatEnd(false), indent(0), detectIndent(false), eatLeadingWhitespace(0), escape(0), fold(false), + trimTrailingSpaces(0), chomp(CLIP), onDocIndicator(NONE), onTabInIndentation(NONE), leadingSpaces(false) {} + // input: RegEx end; // what condition ends this scalar? bool eatEnd; // should we eat that condition when we see it? int indent; // what level of indentation should be eaten and ignored? + bool detectIndent; // should we try to autodetect the indent? bool eatLeadingWhitespace; // should we continue eating this delicious indentation after 'indent' spaces? char escape; // what character do we escape on (i.e., slash or single quote) (0 for none) bool fold; // do we fold line ends? bool trimTrailingSpaces; // do we remove all trailing spaces (at the very end) CHOMP chomp; // do we strip, clip, or keep trailing newlines (at the very end) // Note: strip means kill all, clip means keep at most one, keep means keep all + ACTION onDocIndicator; // what do we do if we see a document indicator? + ACTION onTabInIndentation; // what do we do if we see a tab where we should be seeing indentation spaces + + // output: + bool leadingSpaces; }; - void GetBlockIndentation(Stream& INPUT, int& indent, std::string& breaks, int topIndent); - std::string ScanScalar(Stream& INPUT, ScanScalarInfo info); - - struct WhitespaceInfo { - WhitespaceInfo(); - - void SetChompers(char ch); - void AddBlank(char ch); - void AddBreak(const std::string& line); - std::string Join(bool lastline = false); - - bool leadingBlanks; - bool fold; - std::string whitespace, leadingBreaks, trailingBreaks; - int chomp, increment; - }; + std::string ScanScalar(Stream& INPUT, ScanScalarInfo& info); } diff --git a/test.yaml b/test.yaml index a7221f0..ef3aeb2 100644 --- a/test.yaml +++ b/test.yaml @@ -1,14 +1,17 @@ --- -- "quoted scalar\twith a tab\nand a newline" -- 'This is Jesse''s single quote!' -- | - here's a literal: - #include - - int main() - { - std::cout << "Hello World!\n"; - return 0; - } -- key1: value1 - key2: value2 \ No newline at end of file +- here's a key: value + here's the first block: | + after the block: value + and here's a block: |- + What's going on? + How are you doing? + Here's some code: + + #include + int main() + { + std::cout << "Hello World!\n"; + } + + I'm doing fine! + and last key: value \ No newline at end of file From b58c0c94e4e12094b18a956d314b1ed2d8edc747 Mon Sep 17 00:00:00 2001 From: beder Date: Mon, 30 Jun 2008 01:38:32 +0000 Subject: [PATCH 027/295] Moved the three scalar token scanning functions back to scantoken.cpp, so scanscalar.cpp now only has the main scalar scanning function. Renamed ScanScalarInfo to ScanScalarParams. --- scanscalar.cpp | 174 +++++++++---------------------------------------- scanscalar.h | 6 +- scantoken.cpp | 121 ++++++++++++++++++++++++++++++++++ test.yaml | 112 ++++++++++++++++++++++++++----- 4 files changed, 252 insertions(+), 161 deletions(-) diff --git a/scanscalar.cpp b/scanscalar.cpp index b3577f5..9026d91 100644 --- a/scanscalar.cpp +++ b/scanscalar.cpp @@ -7,39 +7,48 @@ namespace YAML { // ScanScalar - std::string ScanScalar(Stream& INPUT, ScanScalarInfo& info) + // . This is where the scalar magic happens. + // + // . We do the scanning in three phases: + // 1. Scan until newline + // 2. Eat newline + // 3. Scan leading blanks. + // + // . Depending on the parameters given, we store or stop + // and different places in the above flow. + std::string ScanScalar(Stream& INPUT, ScanScalarParams& params) { bool foundNonEmptyLine = false; bool emptyLine = false, moreIndented = false; std::string scalar; - info.leadingSpaces = false; + params.leadingSpaces = false; while(INPUT) { // ******************************** // Phase #1: scan until line ending - while(!info.end.Matches(INPUT) && !Exp::Break.Matches(INPUT)) { + while(!params.end.Matches(INPUT) && !Exp::Break.Matches(INPUT)) { if(INPUT.peek() == EOF) break; // document indicator? if(INPUT.column == 0 && Exp::DocIndicator.Matches(INPUT)) { - if(info.onDocIndicator == BREAK) + if(params.onDocIndicator == BREAK) break; - else if(info.onDocIndicator == THROW) + else if(params.onDocIndicator == THROW) throw IllegalDocIndicator(); } foundNonEmptyLine = true; // escaped newline? (only if we're escaping on slash) - if(info.escape == '\\' && Exp::EscBreak.Matches(INPUT)) { + if(params.escape == '\\' && Exp::EscBreak.Matches(INPUT)) { int n = Exp::EscBreak.Match(INPUT); INPUT.Eat(n); continue; } // escape this? - if(INPUT.peek() == info.escape) { + if(INPUT.peek() == params.escape) { scalar += Exp::Escape(INPUT); continue; } @@ -50,19 +59,19 @@ namespace YAML // eof? if we're looking to eat something, then we throw if(INPUT.peek() == EOF) { - if(info.eatEnd) + if(params.eatEnd) throw IllegalEOF(); break; } // doc indicator? - if(info.onDocIndicator == BREAK && INPUT.column == 0 && Exp::DocIndicator.Matches(INPUT)) + if(params.onDocIndicator == BREAK && INPUT.column == 0 && Exp::DocIndicator.Matches(INPUT)) break; // are we done via character match? - int n = info.end.Match(INPUT); + int n = params.end.Match(INPUT); if(n >= 0) { - if(info.eatEnd) + if(params.eatEnd) INPUT.Eat(n); break; } @@ -76,20 +85,20 @@ namespace YAML // Phase #3: scan initial spaces // first the required indentation - while(INPUT.peek() == ' ' && (INPUT.column < info.indent || (info.detectIndent && !foundNonEmptyLine))) + while(INPUT.peek() == ' ' && (INPUT.column < params.indent || (params.detectIndent && !foundNonEmptyLine))) INPUT.Eat(1); // update indent if we're auto-detecting - if(info.detectIndent && !foundNonEmptyLine) - info.indent = std::max(info.indent, INPUT.column); + if(params.detectIndent && !foundNonEmptyLine) + params.indent = std::max(params.indent, INPUT.column); // and then the rest of the whitespace while(Exp::Blank.Matches(INPUT)) { // we check for tabs that masquerade as indentation - if(INPUT.peek() == '\t'&& INPUT.column < info.indent && info.onTabInIndentation == THROW) + if(INPUT.peek() == '\t'&& INPUT.column < params.indent && params.onTabInIndentation == THROW) throw IllegalTabInIndentation(); - if(!info.eatLeadingWhitespace) + if(!params.eatLeadingWhitespace) break; INPUT.Eat(1); @@ -101,7 +110,7 @@ namespace YAML // TODO: for block scalars, we always start with a newline, so we should fold OR keep that - if(info.fold && !emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented) + if(params.fold && !emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented) scalar += " "; else scalar += "\n"; @@ -110,146 +119,27 @@ namespace YAML moreIndented = nextMoreIndented; // are we done via indentation? - if(!emptyLine && INPUT.column < info.indent) { - info.leadingSpaces = true; + if(!emptyLine && INPUT.column < params.indent) { + params.leadingSpaces = true; break; } } // post-processing - if(info.trimTrailingSpaces) { + if(params.trimTrailingSpaces) { unsigned pos = scalar.find_last_not_of(' '); if(pos < scalar.size()) scalar.erase(pos + 1); } - if(info.chomp <= 0) { + if(params.chomp <= 0) { unsigned pos = scalar.find_last_not_of('\n'); - if(info.chomp == 0 && pos + 1 < scalar.size()) + if(params.chomp == 0 && pos + 1 < scalar.size()) scalar.erase(pos + 2); - else if(info.chomp == -1 && pos < scalar.size()) + else if(params.chomp == -1 && pos < scalar.size()) scalar.erase(pos + 1); } return scalar; } - - // PlainScalarToken - template <> PlainScalarToken *Scanner::ScanToken(PlainScalarToken *pToken) - { - // set up the scanning parameters - ScanScalarInfo info; - info.end = (m_flowLevel > 0 ? Exp::EndScalarInFlow : Exp::EndScalar) || (RegEx(' ') + Exp::Comment); - info.eatEnd = false; - info.indent = (m_flowLevel > 0 ? 0 : m_indents.top() + 1); - info.fold = true; - info.eatLeadingWhitespace = true; - info.trimTrailingSpaces = true; - info.chomp = CLIP; - info.onDocIndicator = BREAK; - info.onTabInIndentation = THROW; - - // insert a potential simple key - if(m_simpleKeyAllowed) - InsertSimpleKey(); - - pToken->value = ScanScalar(INPUT, info); - - // can have a simple key only if we ended the scalar by starting a new line - m_simpleKeyAllowed = info.leadingSpaces; - - // finally, we can't have any colons in a scalar, so if we ended on a colon, there - // had better be a break after it - if(Exp::IllegalColonInScalar.Matches(INPUT)) - throw IllegalScalar(); - - return pToken; - } - - // QuotedScalarToken - template <> QuotedScalarToken *Scanner::ScanToken(QuotedScalarToken *pToken) - { - // eat single or double quote - char quote = INPUT.GetChar(); - pToken->single = (quote == '\''); - - // setup the scanning parameters - ScanScalarInfo info; - info.end = (pToken->single ? RegEx(quote) && !Exp::EscSingleQuote : RegEx(quote)); - info.eatEnd = true; - info.escape = (pToken->single ? '\'' : '\\'); - info.indent = 0; - info.fold = true; - info.eatLeadingWhitespace = true; - info.trimTrailingSpaces = false; - info.chomp = CLIP; - info.onDocIndicator = THROW; - - // insert a potential simple key - if(m_simpleKeyAllowed) - InsertSimpleKey(); - - pToken->value = ScanScalar(INPUT, info); - m_simpleKeyAllowed = false; - - return pToken; - } - - // BlockScalarToken - // . These need a little extra processing beforehand. - // . We need to scan the line where the indicator is (this doesn't count as part of the scalar), - // and then we need to figure out what level of indentation we'll be using. - template <> BlockScalarToken *Scanner::ScanToken(BlockScalarToken *pToken) - { - ScanScalarInfo info; - info.indent = 1; - info.detectIndent = true; - - // eat block indicator ('|' or '>') - char indicator = INPUT.GetChar(); - info.fold = (indicator == Keys::FoldedScalar); - - // eat chomping/indentation indicators - int n = Exp::Chomp.Match(INPUT); - for(int i=0;i= 0) - info.indent += m_indents.top(); - - info.eatLeadingWhitespace = false; - info.trimTrailingSpaces = false; - info.onTabInIndentation = THROW; - - pToken->value = ScanScalar(INPUT, info); - - // simple keys always ok after block scalars (since we're gonna start a new line anyways) - m_simpleKeyAllowed = true; - return pToken; - } } diff --git a/scanscalar.h b/scanscalar.h index c3d0030..b2c4327 100644 --- a/scanscalar.h +++ b/scanscalar.h @@ -9,8 +9,8 @@ namespace YAML enum CHOMP { STRIP = -1, CLIP, KEEP }; enum ACTION { NONE, BREAK, THROW }; - struct ScanScalarInfo { - ScanScalarInfo(): eatEnd(false), indent(0), detectIndent(false), eatLeadingWhitespace(0), escape(0), fold(false), + struct ScanScalarParams { + ScanScalarParams(): eatEnd(false), indent(0), detectIndent(false), eatLeadingWhitespace(0), escape(0), fold(false), trimTrailingSpaces(0), chomp(CLIP), onDocIndicator(NONE), onTabInIndentation(NONE), leadingSpaces(false) {} // input: @@ -31,5 +31,5 @@ namespace YAML bool leadingSpaces; }; - std::string ScanScalar(Stream& INPUT, ScanScalarInfo& info); + std::string ScanScalar(Stream& INPUT, ScanScalarParams& info); } diff --git a/scantoken.cpp b/scantoken.cpp index 6eefa8a..e1d2f1b 100644 --- a/scantoken.cpp +++ b/scantoken.cpp @@ -2,6 +2,7 @@ #include "token.h" #include "exceptions.h" #include "exp.h" +#include "scanscalar.h" namespace YAML { @@ -220,4 +221,124 @@ namespace YAML pToken->value = tag; return pToken; } + + // PlainScalarToken + template <> PlainScalarToken *Scanner::ScanToken(PlainScalarToken *pToken) + { + // set up the scanning parameters + ScanScalarParams params; + params.end = (m_flowLevel > 0 ? Exp::EndScalarInFlow : Exp::EndScalar) || (RegEx(' ') + Exp::Comment); + params.eatEnd = false; + params.indent = (m_flowLevel > 0 ? 0 : m_indents.top() + 1); + params.fold = true; + params.eatLeadingWhitespace = true; + params.trimTrailingSpaces = true; + params.chomp = CLIP; + params.onDocIndicator = BREAK; + params.onTabInIndentation = THROW; + + // insert a potential simple key + if(m_simpleKeyAllowed) + InsertSimpleKey(); + + pToken->value = ScanScalar(INPUT, params); + + // can have a simple key only if we ended the scalar by starting a new line + m_simpleKeyAllowed = params.leadingSpaces; + + // finally, we can't have any colons in a scalar, so if we ended on a colon, there + // had better be a break after it + if(Exp::IllegalColonInScalar.Matches(INPUT)) + throw IllegalScalar(); + + return pToken; + } + + // QuotedScalarToken + template <> QuotedScalarToken *Scanner::ScanToken(QuotedScalarToken *pToken) + { + // eat single or double quote + char quote = INPUT.GetChar(); + pToken->single = (quote == '\''); + + // setup the scanning parameters + ScanScalarParams params; + params.end = (pToken->single ? RegEx(quote) && !Exp::EscSingleQuote : RegEx(quote)); + params.eatEnd = true; + params.escape = (pToken->single ? '\'' : '\\'); + params.indent = 0; + params.fold = true; + params.eatLeadingWhitespace = true; + params.trimTrailingSpaces = false; + params.chomp = CLIP; + params.onDocIndicator = THROW; + + // insert a potential simple key + if(m_simpleKeyAllowed) + InsertSimpleKey(); + + pToken->value = ScanScalar(INPUT, params); + m_simpleKeyAllowed = false; + + return pToken; + } + + // BlockScalarToken + // . These need a little extra processing beforehand. + // . We need to scan the line where the indicator is (this doesn't count as part of the scalar), + // and then we need to figure out what level of indentation we'll be using. + template <> BlockScalarToken *Scanner::ScanToken(BlockScalarToken *pToken) + { + ScanScalarParams params; + params.indent = 1; + params.detectIndent = true; + + // eat block indicator ('|' or '>') + char indicator = INPUT.GetChar(); + params.fold = (indicator == Keys::FoldedScalar); + + // eat chomping/indentation indicators + int n = Exp::Chomp.Match(INPUT); + for(int i=0;i= 0) + params.indent += m_indents.top(); + + params.eatLeadingWhitespace = false; + params.trimTrailingSpaces = false; + params.onTabInIndentation = THROW; + + pToken->value = ScanScalar(INPUT, params); + + // simple keys always ok after block scalars (since we're gonna start a new line anyways) + m_simpleKeyAllowed = true; + return pToken; + } } diff --git a/test.yaml b/test.yaml index ef3aeb2..8a9714c 100644 --- a/test.yaml +++ b/test.yaml @@ -1,17 +1,97 @@ --- -- here's a key: value - here's the first block: | - after the block: value - and here's a block: |- - What's going on? - How are you doing? - Here's some code: - - #include - int main() - { - std::cout << "Hello World!\n"; - } - - I'm doing fine! - and last key: value \ No newline at end of file +model: + file: data/models/compound.model + textures: data/materials/compound +rooms: + - name: "Room #1" + pos: [0, 0, 0] + size: [1000, 1000, 500] + height: 500 + stairtype: none + display: [] + pathfinding: + tilesize: 50 + size: [24, 24] + map: | + ----------------------- + -+++++++++++++++++++++- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+--------------------- + -+--------------------- + -+--------------------- + -+--------------------- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+++++++++++++++++++++- + ----------------------- + - name: Doorway + pos: [1000, 400, 0] + size: [50, 200, 500] + height: 500 + stairtype: none + display: [] + pathfinding: + tilesize: 50 + size: [5, 9] + map: | + ----- + -+++- + ----- + ----- + ----- + ----- + ----- + -+++- + ----- + - name: "Room #2" + pos: [1050, 0, 0] + size: [1000, 1000, 500] + height: 500 + stairtype: none + display: [] + pathfinding: + tilesize: 50 + size: [24, 24] + map: | + ----------------------- + -+++++++++++++++++++++- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + ---------------------+- + ---------------------+- + ---------------------+- + ---------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+++++++++++++++++++++- + ----------------------- +exits: + - room1: "Room #1" + room2: "Room #2" + dir: e + pos: [400, 600] From a93584b065addaa21c81a786fc442c0bb8622414 Mon Sep 17 00:00:00 2001 From: beder Date: Mon, 30 Jun 2008 04:22:41 +0000 Subject: [PATCH 028/295] Added directives and tags. --- exp.h | 1 + scanner.cpp | 70 ++++++----------------------- scanner.h | 6 --- scantoken.cpp | 66 +++++++++++++++++++++++++++ test.yaml | 121 +++++++++++--------------------------------------- token.h | 15 +++++++ 6 files changed, 120 insertions(+), 159 deletions(-) diff --git a/exp.h b/exp.h index ea1804b..652e2bd 100644 --- a/exp.h +++ b/exp.h @@ -57,6 +57,7 @@ namespace YAML namespace Keys { + const char Directive = '%'; const char FlowSeqStart = '['; const char FlowSeqEnd = ']'; const char FlowMapStart = '{'; diff --git a/scanner.cpp b/scanner.cpp index 5e83907..fb49bbd 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -44,56 +44,6 @@ namespace YAML return false; } - // IsDocumentStart - bool Scanner::IsDocumentStart() - { - // needs to be at the start of a new line - if(INPUT.column != 0) - return false; - - return Exp::DocStart.Matches(INPUT); - } - - // IsDocumentEnd - bool Scanner::IsDocumentEnd() - { - // needs to be at the start of a new line - if(INPUT.column != 0) - return false; - - return Exp::DocEnd.Matches(INPUT); - } - - // IsBlockEntry - bool Scanner::IsBlockEntry() - { - return Exp::BlockEntry.Matches(INPUT); - } - - // IsKey - bool Scanner::IsKey() - { - if(m_flowLevel > 0) - return Exp::KeyInFlow.Matches(INPUT); - return Exp::Key.Matches(INPUT); - } - - // IsValue - bool Scanner::IsValue() - { - if(m_flowLevel > 0) - return Exp::ValueInFlow.Matches(INPUT); - return Exp::Value.Matches(INPUT); - } - - // IsPlainScalar - bool Scanner::IsPlainScalar() - { - if(m_flowLevel > 0) - return Exp::PlainScalarInFlow.Matches(INPUT); - return Exp::PlainScalar.Matches(INPUT); - } - // ScanAndEnqueue // . Scans the token, then pushes it in the queue. // . Note: we also use a set of "limbo tokens", i.e., tokens @@ -136,11 +86,14 @@ namespace YAML if(INPUT.peek() == EOF) return ScanAndEnqueue(new StreamEndToken); + if(INPUT.column == 0 && INPUT.peek() == Keys::Directive) + return ScanAndEnqueue(new DirectiveToken); + // document token - if(IsDocumentStart()) + if(INPUT.column == 0 && Exp::DocStart.Matches(INPUT)) return ScanAndEnqueue(new DocumentStartToken); - if(IsDocumentEnd()) + if(INPUT.column == 0 && Exp::DocEnd.Matches(INPUT)) return ScanAndEnqueue(new DocumentEndToken); // flow start/end/entry @@ -160,19 +113,22 @@ namespace YAML return ScanAndEnqueue(new FlowEntryToken); // block/map stuff - if(IsBlockEntry()) + if(Exp::BlockEntry.Matches(INPUT)) return ScanAndEnqueue(new BlockEntryToken); - if(IsKey()) + if((m_flowLevel == 0 ? Exp::Key : Exp::KeyInFlow).Matches(INPUT)) return ScanAndEnqueue(new KeyToken); - if(IsValue()) + if((m_flowLevel == 0 ? Exp::Value : Exp::ValueInFlow).Matches(INPUT)) return ScanAndEnqueue(new ValueToken); + // alias/anchor if(INPUT.peek() == Keys::Alias || INPUT.peek() == Keys::Anchor) return ScanAndEnqueue(new AnchorToken); - // TODO: tag + // tag + if(INPUT.peek() == Keys::Tag) + return ScanAndEnqueue(new TagToken); // special scalars if(m_flowLevel == 0 && (INPUT.peek() == Keys::LiteralScalar || INPUT.peek() == Keys::FoldedScalar)) @@ -182,7 +138,7 @@ namespace YAML return ScanAndEnqueue(new QuotedScalarToken); // plain scalars - if(IsPlainScalar()) + if((m_flowLevel == 0 ? Exp::PlainScalar : Exp::PlainScalarInFlow).Matches(INPUT)) return ScanAndEnqueue(new PlainScalarToken); // don't know what it is! diff --git a/scanner.h b/scanner.h index fd5ad1a..cf402ca 100644 --- a/scanner.h +++ b/scanner.h @@ -34,12 +34,6 @@ namespace YAML void VerifyAllSimpleKeys(); bool IsWhitespaceToBeEaten(char ch); - bool IsDocumentStart(); - bool IsDocumentEnd(); - bool IsBlockEntry(); - bool IsKey(); - bool IsValue(); - bool IsPlainScalar(); struct SimpleKey { SimpleKey(int pos_, int line_, int column_, int flowLevel_); diff --git a/scantoken.cpp b/scantoken.cpp index e1d2f1b..f9ea4bf 100644 --- a/scantoken.cpp +++ b/scantoken.cpp @@ -35,6 +35,44 @@ namespace YAML return pToken; } + // DirectiveToken + // . Note: no semantic checking is done here (that's for the parser to do) + template <> DirectiveToken *Scanner::ScanToken(DirectiveToken *pToken) + { + // pop indents and simple keys + PopIndentTo(-1); + VerifyAllSimpleKeys(); + + m_simpleKeyAllowed = false; + + // eat indicator + INPUT.Eat(1); + + // read name + while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT)) + pToken->name += INPUT.GetChar(); + + // read parameters + while(1) { + // first get rid of whitespace + while(Exp::Blank.Matches(INPUT)) + INPUT.Eat(1); + + // break on newline or comment + if(INPUT.peek() == EOF || Exp::Break.Matches(INPUT) || Exp::Comment.Matches(INPUT)) + break; + + // now read parameter + std::string param; + while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT)) + param += INPUT.GetChar(); + + pToken->params.push_back(param); + } + + return pToken; + } + // DocumentStartToken template <> DocumentStartToken *Scanner::ScanToken(DocumentStartToken *pToken) { @@ -222,6 +260,34 @@ namespace YAML return pToken; } + // TagToken + template <> TagToken *Scanner::ScanToken(TagToken *pToken) + { + // insert a potential simple key + if(m_simpleKeyAllowed) + InsertSimpleKey(); + m_simpleKeyAllowed = false; + + // eat the indicator + INPUT.Eat(1); + + // read the handle + while(INPUT.peek() != EOF && INPUT.peek() != Keys::Tag && !Exp::BlankOrBreak.Matches(INPUT)) + pToken->handle += INPUT.GetChar(); + + // is there a suffix? + if(INPUT.peek() == Keys::Tag) { + // eat the indicator + INPUT.Eat(1); + + // then read it + while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT)) + pToken->suffix += INPUT.GetChar(); + } + + return pToken; + } + // PlainScalarToken template <> PlainScalarToken *Scanner::ScanToken(PlainScalarToken *pToken) { diff --git a/test.yaml b/test.yaml index 8a9714c..6b1ccb2 100644 --- a/test.yaml +++ b/test.yaml @@ -1,97 +1,26 @@ --- -model: - file: data/models/compound.model - textures: data/materials/compound -rooms: - - name: "Room #1" - pos: [0, 0, 0] - size: [1000, 1000, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [24, 24] - map: | - ----------------------- - -+++++++++++++++++++++- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+--------------------- - -+--------------------- - -+--------------------- - -+--------------------- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+++++++++++++++++++++- - ----------------------- - - name: Doorway - pos: [1000, 400, 0] - size: [50, 200, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [5, 9] - map: | - ----- - -+++- - ----- - ----- - ----- - ----- - ----- - -+++- - ----- - - name: "Room #2" - pos: [1050, 0, 0] - size: [1000, 1000, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [24, 24] - map: | - ----------------------- - -+++++++++++++++++++++- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - ---------------------+- - ---------------------+- - ---------------------+- - ---------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+++++++++++++++++++++- - ----------------------- -exits: - - room1: "Room #1" - room2: "Room #2" - dir: e - pos: [400, 600] +Time: 2001-11-23 15:01:42 -5 +User: ed +Warning: + This is an error message + for the log file +--- +Time: 2001-11-23 15:02:31 -5 +User: ed +Warning: + A slightly different error + message. +--- +Date: 2001-11-23 15:03:17 -5 +User: ed +Fatal: + Unknown variable "bar" +Stack: + - file: TopClass.py + line: 23 + code: | + x = MoreObject("345\n") + - file: MoreClass.py + line: 58 + code: |- + foo = bar \ No newline at end of file diff --git a/token.h b/token.h index 70fd7fd..3a3bff5 100644 --- a/token.h +++ b/token.h @@ -1,6 +1,8 @@ #pragma once #include +#include +#include namespace YAML { @@ -17,6 +19,13 @@ namespace YAML struct StreamStartToken: public Token {}; struct StreamEndToken: public Token {}; + struct DirectiveToken: public Token { + std::string name; + std::vector params; + + virtual void Write(std::ostream& out) const { out << name; for(unsigned i=0;i Date: Mon, 30 Jun 2008 06:21:12 +0000 Subject: [PATCH 029/295] Added a peek token command (for the parser to use). --- document.cpp | 15 ++++- exceptions.h | 35 +++++------ scanner.cpp | 161 +++++++++++++++++++++++++-------------------------- scanner.h | 2 +- stream.cpp | 8 --- stream.h | 1 - 6 files changed, 109 insertions(+), 113 deletions(-) diff --git a/document.cpp b/document.cpp index ca07e66..cb5c7cf 100644 --- a/document.cpp +++ b/document.cpp @@ -5,6 +5,9 @@ #include "exceptions.h" #include +#include +#include "token.h" + namespace YAML { Document::Document(): m_pRoot(0) @@ -34,10 +37,16 @@ namespace YAML std::ifstream fin(fileName.c_str()); Scanner scanner(fin); - scanner.Scan(); + // scan and output, for now + while(1) { + Token *pToken = scanner.GetNextToken(); + if(!pToken) + break; + + std::cout << typeid(*pToken).name() << ": " << *pToken << std::endl; + delete pToken; + } getchar(); -// if(!scanner) -// return; // m_pRoot = parser.ReadNextNode(); } diff --git a/exceptions.h b/exceptions.h index 3c66d85..9c5df62 100644 --- a/exceptions.h +++ b/exceptions.h @@ -5,33 +5,34 @@ namespace YAML { class Exception: public std::exception {}; + class ScannerException: public Exception {}; - class UnknownToken: public Exception {}; - class IllegalBlockEntry: public Exception {}; - class IllegalMapKey: public Exception {}; - class IllegalMapValue: public Exception {}; - class IllegalScalar: public Exception {}; - class IllegalTabInIndentation: public Exception {}; - class IllegalFlowEnd: public Exception {}; - class IllegalDocIndicator: public Exception {}; - class IllegalEOF: public Exception {}; - class RequiredSimpleKeyNotFound: public Exception {}; - class ZeroIndentationInBlockScalar: public Exception {}; - class UnexpectedCharacterInBlockScalar: public Exception {}; - class AnchorNotFound: public Exception {}; - class IllegalCharacterInAnchor: public Exception {}; + class UnknownToken: public ScannerException {}; + class IllegalBlockEntry: public ScannerException {}; + class IllegalMapKey: public ScannerException {}; + class IllegalMapValue: public ScannerException {}; + class IllegalScalar: public ScannerException {}; + class IllegalTabInIndentation: public ScannerException {}; + class IllegalFlowEnd: public ScannerException {}; + class IllegalDocIndicator: public ScannerException {}; + class IllegalEOF: public ScannerException {}; + class RequiredSimpleKeyNotFound: public ScannerException {}; + class ZeroIndentationInBlockScalar: public ScannerException {}; + class UnexpectedCharacterInBlockScalar: public ScannerException {}; + class AnchorNotFound: public ScannerException {}; + class IllegalCharacterInAnchor: public ScannerException {}; - class UnknownEscapeSequence: public Exception { + class UnknownEscapeSequence: public ScannerException { public: UnknownEscapeSequence(char ch_): ch(ch_) {} char ch; }; - class NonHexNumber: public Exception { + class NonHexNumber: public ScannerException { public: NonHexNumber(char ch_): ch(ch_) {} char ch; }; - class InvalidUnicode: public Exception { + class InvalidUnicode: public ScannerException { public: InvalidUnicode(unsigned value_): value(value_) {} unsigned value; diff --git a/scanner.cpp b/scanner.cpp index fb49bbd..c3e82ec 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -2,7 +2,6 @@ #include "token.h" #include "exceptions.h" #include "exp.h" -#include namespace YAML { @@ -23,39 +22,51 @@ namespace YAML delete *it; } - /////////////////////////////////////////////////////////////////////// - // Misc. helpers - - // IsWhitespaceToBeEaten - // . We can eat whitespace if: - // 1. It's a space - // 2. It's a tab, and we're either: - // a. In the flow context - // b. In the block context but not where a simple key could be allowed - // (i.e., not at the beginning of a line, or following '-', '?', or ':') - bool Scanner::IsWhitespaceToBeEaten(char ch) + // GetNextToken + // . Removes and returns the next token on the queue. + Token *Scanner::GetNextToken() { - if(ch == ' ') - return true; - - if(ch == '\t' && (m_flowLevel >= 0 || !m_simpleKeyAllowed)) - return true; - - return false; + Token *pToken = PeekNextToken(); + if(!m_tokens.empty()) + m_tokens.pop(); + return pToken; } - // ScanAndEnqueue - // . Scans the token, then pushes it in the queue. - // . Note: we also use a set of "limbo tokens", i.e., tokens - // that haven't yet been pushed. This way, if ScanToken() - // throws an exception, we'll be keeping track of 'pToken' - // somewhere, and it will be automatically cleaned up when - // the Scanner destructs. - template void Scanner::ScanAndEnqueue(T *pToken) + // PeekNextToken + // . Returns (but does not remove) the next token on the queue, and scans if only we need to. + Token *Scanner::PeekNextToken() { - m_limboTokens.insert(pToken); - m_tokens.push(ScanToken(pToken)); - m_limboTokens.erase(pToken); + while(1) { + Token *pToken = 0; + + // is there a token in the queue? + if(!m_tokens.empty()) + pToken = m_tokens.front(); + + // (here's where we clean up the impossible tokens) + if(pToken && pToken->status == TS_INVALID) { + m_tokens.pop(); + delete pToken; + continue; + } + + // on unverified tokens, we just have to wait + if(pToken && pToken->status == TS_UNVERIFIED) + pToken = 0; + + // then that's what we want + if(pToken) + return pToken; + + // no token? maybe we've actually finished + if(m_endedStream) + break; + + // no? then scan... + ScanNextToken(); + } + + return 0; } // ScanNextToken @@ -166,7 +177,8 @@ namespace YAML break; // otherwise, let's eat the line break and keep going - INPUT.EatLineBreak(); + int n = Exp::Break.Match(INPUT); + INPUT.Eat(n); // oh yeah, and let's get rid of that simple key VerifySimpleKey(); @@ -177,6 +189,41 @@ namespace YAML } } + /////////////////////////////////////////////////////////////////////// + // Misc. helpers + + // IsWhitespaceToBeEaten + // . We can eat whitespace if: + // 1. It's a space + // 2. It's a tab, and we're either: + // a. In the flow context + // b. In the block context but not where a simple key could be allowed + // (i.e., not at the beginning of a line, or following '-', '?', or ':') + bool Scanner::IsWhitespaceToBeEaten(char ch) + { + if(ch == ' ') + return true; + + if(ch == '\t' && (m_flowLevel >= 0 || !m_simpleKeyAllowed)) + return true; + + return false; + } + + // ScanAndEnqueue + // . Scans the token, then pushes it in the queue. + // . Note: we also use a set of "limbo tokens", i.e., tokens + // that haven't yet been pushed. This way, if ScanToken() + // throws an exception, we'll be keeping track of 'pToken' + // somewhere, and it will be automatically cleaned up when + // the Scanner destructs. + template void Scanner::ScanAndEnqueue(T *pToken) + { + m_limboTokens.insert(pToken); + m_tokens.push(ScanToken(pToken)); + m_limboTokens.erase(pToken); + } + // PushIndentTo // . Pushes an indentation onto the stack, and enqueues the // proper token (sequence start or mapping start). @@ -216,56 +263,4 @@ namespace YAML m_tokens.push(new BlockEndToken); } } - - // GetNextToken - // . Returns the next token on the queue, and scans if only we need to. - Token *Scanner::GetNextToken() - { - while(1) { - Token *pToken = 0; - - // is there a token in the queue? - if(!m_tokens.empty()) - pToken = m_tokens.front(); - - // (here's where we clean up the impossible tokens) - if(pToken && pToken->status == TS_INVALID) { - m_tokens.pop(); - delete pToken; - continue; - } - - // on unverified tokens, we just have to wait - if(pToken && pToken->status == TS_UNVERIFIED) - pToken = 0; - - // then that's what we want - if(pToken) { - m_tokens.pop(); - return pToken; - } - - // no token? maybe we've actually finished - if(m_endedStream) - break; - - // no? then scan... - ScanNextToken(); - } - - return 0; - } - - // temporary function for testing - void Scanner::Scan() - { - while(1) { - Token *pToken = GetNextToken(); - if(!pToken) - break; - - std::cout << typeid(*pToken).name() << ": " << *pToken << std::endl; - delete pToken; - } - } } diff --git a/scanner.h b/scanner.h index cf402ca..8f711cb 100644 --- a/scanner.h +++ b/scanner.h @@ -19,7 +19,7 @@ namespace YAML ~Scanner(); Token *GetNextToken(); - void Scan(); + Token *PeekNextToken(); private: // scanning diff --git a/stream.cpp b/stream.cpp index b4a5050..e7e3010 100644 --- a/stream.cpp +++ b/stream.cpp @@ -32,12 +32,4 @@ namespace YAML for(int i=0;i Date: Mon, 30 Jun 2008 06:51:22 +0000 Subject: [PATCH 030/295] Started the parser. --- document.cpp | 33 ----------- document.h | 4 -- main.cpp | 9 ++- node.cpp | 11 ---- node.h | 2 - parser.cpp | 140 ++++++--------------------------------------- parser.h | 40 ++----------- reader.cpp | 21 +++++++ reader.h | 21 +++++++ sequence.cpp | 13 +---- sequence.h | 5 +- yaml-reader.vcproj | 120 ++++++++++++++++++++++---------------- 12 files changed, 143 insertions(+), 276 deletions(-) create mode 100644 reader.cpp create mode 100644 reader.h diff --git a/document.cpp b/document.cpp index cb5c7cf..74286e9 100644 --- a/document.cpp +++ b/document.cpp @@ -1,12 +1,5 @@ #include "document.h" #include "node.h" -#include "parser.h" -#include "scanner.h" -#include "exceptions.h" -#include - -#include -#include "token.h" namespace YAML { @@ -14,11 +7,6 @@ namespace YAML { } - Document::Document(const std::string& fileName): m_pRoot(0) - { - Load(fileName); - } - Document::~Document() { Clear(); @@ -29,25 +17,4 @@ namespace YAML delete m_pRoot; m_pRoot = 0; } - - void Document::Load(const std::string& fileName) - { - Clear(); - - std::ifstream fin(fileName.c_str()); - Scanner scanner(fin); - - // scan and output, for now - while(1) { - Token *pToken = scanner.GetNextToken(); - if(!pToken) - break; - - std::cout << typeid(*pToken).name() << ": " << *pToken << std::endl; - delete pToken; - } - getchar(); - -// m_pRoot = parser.ReadNextNode(); - } } diff --git a/document.h b/document.h index 285bf94..62be716 100644 --- a/document.h +++ b/document.h @@ -1,7 +1,5 @@ #pragma once -#include - namespace YAML { class Node; @@ -10,11 +8,9 @@ namespace YAML { public: Document(); - Document(const std::string& fileName); ~Document(); void Clear(); - void Load(const std::string& fileName); private: Node *m_pRoot; diff --git a/main.cpp b/main.cpp index 5e02ba3..2a8898a 100644 --- a/main.cpp +++ b/main.cpp @@ -1,9 +1,12 @@ -#include "document.h" -#include "regex.h" +#include "reader.h" +#include int main() { - YAML::Document doc("test.yaml"); + std::ifstream fin("test.yaml"); + YAML::Reader reader(fin); + YAML::Document doc; + reader.GetNextDocument(doc); return 0; } \ No newline at end of file diff --git a/node.cpp b/node.cpp index 33c688f..c3ca6a4 100644 --- a/node.cpp +++ b/node.cpp @@ -20,15 +20,4 @@ namespace YAML delete m_pContent; m_pContent = 0; } - - void Node::Read(Parser *pParser, const std::string& token) - { - Clear(); - - if(token == std::string("") + SeqToken) { - m_pContent = new Sequence(pParser); - } else { - m_pContent = new Scalar(token); - } - } } diff --git a/node.h b/node.h index c8bd7e5..b553faa 100644 --- a/node.h +++ b/node.h @@ -10,7 +10,6 @@ namespace YAML const std::string MapTag = "!!map"; class Content; - class Parser; class Node { @@ -19,7 +18,6 @@ namespace YAML ~Node(); void Clear(); - void Read(Parser *pParser, const std::string& token); private: std::string m_tag; diff --git a/parser.cpp b/parser.cpp index 999fa90..3ec881c 100644 --- a/parser.cpp +++ b/parser.cpp @@ -1,141 +1,33 @@ #include "parser.h" #include "node.h" +#include "token.h" + +#include namespace YAML { - Parser::Parser(std::istream& in): INPUT(in), m_ok(true) + Parser::Parser(std::istream& in): m_scanner(in) { - m_state.push(State(C_BLOCK, -1, true)); - - // read header - std::string token = ReadNextToken(); - if(token != DocStart) - m_ok = false; + // eat the stream start token + // TODO: check? + Token *pToken = m_scanner.GetNextToken(); } Parser::~Parser() { } - Parser::operator bool() const + void Parser::GetNextDocument(Document& document) { - return m_ok; - } + // scan and output, for now + while(1) { + Token *pToken = m_scanner.GetNextToken(); + if(!pToken) + break; - bool Parser::operator !() const - { - return !m_ok; - } - - bool Parser::IsWhitespace(char ch) - { - return (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'); - } - - void Parser::Putback(const std::string& str) - { - for(int i=str.size()-1;i>=0;i--) - INPUT.putback(str[i]); - } - - // StringWhitespace - // . Strips up to n whitespace characters (or as many - // as there are, if n is -1) - void Parser::StripWhitespace(int n) - { - while(--n >= 0 && IsWhitespace(INPUT.peek())) - INPUT.get(); - } - - int Parser::GetNumOfSpaces() - { - // get 'em out - int n = 0; - while(INPUT.peek() == ' ') { - INPUT.get(); - n++; + std::cout << typeid(*pToken).name() << ": " << *pToken << std::endl; + delete pToken; } - - // put 'em back - for(int i=0;iRead(this, token); - return pNode; - } - - // ReadNextToken - // . Reads: - // . If the first character is non-whitespace, non-special token, then until - // the end of this scalar. - std::string Parser::ReadNextToken() - { - const State& state = m_state.top(); - - if(state.startingNewLine) { - int n = GetNumOfSpaces(); - StripWhitespace(n); - if(n > state.indent) { - m_state.push(State(C_BLOCK, n, true)); - }; - - while(m_state.top().startingNewLine && n < m_state.top().indent) - m_state.pop(); - } - - char ch = INPUT.peek(); - if(IsWhitespace(ch)) - return ""; // TODO - - if(ch == SeqToken) { - // grab token - INPUT.get(); - - // is next token whitespace? - if(!IsWhitespace(INPUT.peek())) { - // read entire line - std::string line; - std::getline(INPUT, line); - return ch + line; - } - - // if so, strip whitespace and go - StripWhitespace(); - - return std::string("") + SeqToken; - } - - // read until end-of-line - std::string line; - std::getline(INPUT, line); - return line; + getchar(); } } diff --git a/parser.h b/parser.h index fbbae0b..6b4602b 100644 --- a/parser.h +++ b/parser.h @@ -2,54 +2,22 @@ #include #include -#include +#include "scanner.h" +#include "document.h" namespace YAML { class Node; - const std::string DocStart = "---"; - const std::string DocEnd = "..."; - - const char SeqToken = '-'; - - enum CONTEXT { C_BLOCK, C_FLOW }; - class Parser { - public: - struct State - { - State(CONTEXT context_, int indent_, bool startingNewLine_) - : context(context_), indent(indent_), startingNewLine(startingNewLine_) {} - - CONTEXT context; - int indent; - bool startingNewLine; - }; - public: Parser(std::istream& in); ~Parser(); - operator bool () const; - bool operator !() const; - - // parse helpers - static bool IsWhitespace(char ch); - void Putback(const std::string& str); - void StripWhitespace(int n = -1); - int GetNumOfSpaces(); - bool SeqContinues(); - - // readers - Node *ReadNextNode(); - std::string ReadNextToken(); + void GetNextDocument(Document& document); private: - bool m_ok; - - std::istream& INPUT; - std::stack m_state; + Scanner m_scanner; }; } diff --git a/reader.cpp b/reader.cpp new file mode 100644 index 0000000..4d94459 --- /dev/null +++ b/reader.cpp @@ -0,0 +1,21 @@ +#include "reader.h" +#include "scanner.h" +#include "parser.h" + +namespace YAML +{ + Reader::Reader(std::istream& in): m_pParser(0) + { + m_pParser = new Parser(in); + } + + Reader::~Reader() + { + delete m_pParser; + } + + void Reader::GetNextDocument(Document& document) + { + m_pParser->GetNextDocument(document); + } +} diff --git a/reader.h b/reader.h new file mode 100644 index 0000000..3226af9 --- /dev/null +++ b/reader.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include "document.h" + +namespace YAML +{ + class Parser; + + class Reader + { + public: + Reader(std::istream& in); + ~Reader(); + + void GetNextDocument(Document& document); + + private: + Parser *m_pParser; + }; +} diff --git a/sequence.cpp b/sequence.cpp index c9d3e4c..b02b35f 100644 --- a/sequence.cpp +++ b/sequence.cpp @@ -1,12 +1,11 @@ #include "sequence.h" #include "node.h" -#include "parser.h" namespace YAML { - Sequence::Sequence(Parser *pParser) + Sequence::Sequence() { - Read(pParser); + } Sequence::~Sequence() @@ -14,12 +13,4 @@ namespace YAML for(unsigned i=0;iReadNextNode(); - m_data.push_back(pNode); - } while(pParser->SeqContinues()); - } } diff --git a/sequence.h b/sequence.h index f230505..cf7d1dd 100644 --- a/sequence.h +++ b/sequence.h @@ -6,16 +6,13 @@ namespace YAML { class Node; - class Parser; class Sequence: public Content { public: - Sequence(Parser *pParser); + Sequence(); virtual ~Sequence(); - void Read(Parser *pParser); - protected: std::vector m_data; }; diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index a0ae76d..46a4707 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -169,10 +169,6 @@ RelativePath=".\document.cpp" > - - @@ -186,41 +182,57 @@ > - - - - - - - - - - - + + + + + + + + + + + + + + + - + + + - - @@ -252,37 +260,53 @@ > - - - - - - - - + + + + + + + + + + + + + + + + Date: Mon, 30 Jun 2008 21:47:21 +0000 Subject: [PATCH 031/295] Instead of deriving different tokens from a base Token class, we now use an enumerated TOKEN_TYPE to distinguish types. This is so we don't have to cast all the time when parsing the resulting token stream. Also, removed start/end stream tokens. --- parser.cpp | 5 +- scanner.cpp | 86 +++++++++++----------- scanner.h | 23 +++++- scantoken.cpp | 194 ++++++++++++++++++++++---------------------------- simplekey.cpp | 2 +- token.h | 105 +++++++++++++-------------- 6 files changed, 201 insertions(+), 214 deletions(-) diff --git a/parser.cpp b/parser.cpp index 3ec881c..75c014c 100644 --- a/parser.cpp +++ b/parser.cpp @@ -8,9 +8,6 @@ namespace YAML { Parser::Parser(std::istream& in): m_scanner(in) { - // eat the stream start token - // TODO: check? - Token *pToken = m_scanner.GetNextToken(); } Parser::~Parser() @@ -25,7 +22,7 @@ namespace YAML if(!pToken) break; - std::cout << typeid(*pToken).name() << ": " << *pToken << std::endl; + std::cout << *pToken << std::endl; delete pToken; } getchar(); diff --git a/scanner.cpp b/scanner.cpp index c3e82ec..448a8da 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -16,10 +16,6 @@ namespace YAML delete m_tokens.front(); m_tokens.pop(); } - - // delete limbo tokens (they're here for RAII) - for(std::set ::const_iterator it=m_limboTokens.begin();it!=m_limboTokens.end();++it) - delete *it; } // GetNextToken @@ -78,7 +74,7 @@ namespace YAML return; if(!m_startedStream) - return ScanAndEnqueue(new StreamStartToken); + return StartStream(); // get rid of whitespace, etc. (in between tokens it should be irrelevent) ScanToNextToken(); @@ -95,62 +91,56 @@ namespace YAML // end of stream if(INPUT.peek() == EOF) - return ScanAndEnqueue(new StreamEndToken); + return EndStream(); if(INPUT.column == 0 && INPUT.peek() == Keys::Directive) - return ScanAndEnqueue(new DirectiveToken); + return ScanDirective(); // document token if(INPUT.column == 0 && Exp::DocStart.Matches(INPUT)) - return ScanAndEnqueue(new DocumentStartToken); + return ScanDocStart(); if(INPUT.column == 0 && Exp::DocEnd.Matches(INPUT)) - return ScanAndEnqueue(new DocumentEndToken); + return ScanDocEnd(); // flow start/end/entry - if(INPUT.peek() == Keys::FlowSeqStart) - return ScanAndEnqueue(new FlowSeqStartToken); - - if(INPUT.peek() == Keys::FlowSeqEnd) - return ScanAndEnqueue(new FlowSeqEndToken); - - if(INPUT.peek() == Keys::FlowMapStart) - return ScanAndEnqueue(new FlowMapStartToken); - - if(INPUT.peek() == Keys::FlowMapEnd) - return ScanAndEnqueue(new FlowMapEndToken); + if(INPUT.peek() == Keys::FlowSeqStart || INPUT.peek() == Keys::FlowMapStart) + return ScanFlowStart(); + if(INPUT.peek() == Keys::FlowSeqEnd || INPUT.peek() == Keys::FlowMapEnd) + return ScanFlowEnd(); + if(INPUT.peek() == Keys::FlowEntry) - return ScanAndEnqueue(new FlowEntryToken); + return ScanFlowEntry(); // block/map stuff if(Exp::BlockEntry.Matches(INPUT)) - return ScanAndEnqueue(new BlockEntryToken); + return ScanBlockEntry(); if((m_flowLevel == 0 ? Exp::Key : Exp::KeyInFlow).Matches(INPUT)) - return ScanAndEnqueue(new KeyToken); + return ScanKey(); if((m_flowLevel == 0 ? Exp::Value : Exp::ValueInFlow).Matches(INPUT)) - return ScanAndEnqueue(new ValueToken); + return ScanValue(); // alias/anchor if(INPUT.peek() == Keys::Alias || INPUT.peek() == Keys::Anchor) - return ScanAndEnqueue(new AnchorToken); + return ScanAnchorOrAlias(); // tag if(INPUT.peek() == Keys::Tag) - return ScanAndEnqueue(new TagToken); + return ScanTag(); // special scalars if(m_flowLevel == 0 && (INPUT.peek() == Keys::LiteralScalar || INPUT.peek() == Keys::FoldedScalar)) - return ScanAndEnqueue(new BlockScalarToken); + return ScanBlockScalar(); if(INPUT.peek() == '\'' || INPUT.peek() == '\"') - return ScanAndEnqueue(new QuotedScalarToken); + return ScanQuotedScalar(); // plain scalars if((m_flowLevel == 0 ? Exp::PlainScalar : Exp::PlainScalarInFlow).Matches(INPUT)) - return ScanAndEnqueue(new PlainScalarToken); + return ScanPlainScalar(); // don't know what it is! throw UnknownToken(); @@ -210,18 +200,28 @@ namespace YAML return false; } - // ScanAndEnqueue - // . Scans the token, then pushes it in the queue. - // . Note: we also use a set of "limbo tokens", i.e., tokens - // that haven't yet been pushed. This way, if ScanToken() - // throws an exception, we'll be keeping track of 'pToken' - // somewhere, and it will be automatically cleaned up when - // the Scanner destructs. - template void Scanner::ScanAndEnqueue(T *pToken) + // StartStream + // . Set the initial conditions for starting a stream. + void Scanner::StartStream() { - m_limboTokens.insert(pToken); - m_tokens.push(ScanToken(pToken)); - m_limboTokens.erase(pToken); + m_startedStream = true; + m_simpleKeyAllowed = true; + m_indents.push(-1); + } + + // EndStream + // . Close out the stream, finish up, etc. + void Scanner::EndStream() + { + // force newline + if(INPUT.column > 0) + INPUT.column = 0; + + PopIndentTo(-1); + VerifyAllSimpleKeys(); + + m_simpleKeyAllowed = false; + m_endedStream = true; } // PushIndentTo @@ -241,9 +241,9 @@ namespace YAML // now push m_indents.push(column); if(sequence) - m_tokens.push(new BlockSeqStartToken); + m_tokens.push(new Token(TT_BLOCK_SEQ_START)); else - m_tokens.push(new BlockMapStartToken); + m_tokens.push(new Token(TT_BLOCK_MAP_START)); return m_tokens.front(); } @@ -260,7 +260,7 @@ namespace YAML // now pop away while(!m_indents.empty() && m_indents.top() > column) { m_indents.pop(); - m_tokens.push(new BlockEndToken); + m_tokens.push(new Token(TT_BLOCK_END)); } } } diff --git a/scanner.h b/scanner.h index 8f711cb..f686ba4 100644 --- a/scanner.h +++ b/scanner.h @@ -23,6 +23,8 @@ namespace YAML private: // scanning + void StartStream(); + void EndStream(); void ScanNextToken(); void ScanToNextToken(); Token *PushIndentTo(int column, bool sequence); @@ -46,8 +48,24 @@ namespace YAML Token *pMapStart, *pKey; }; - template void ScanAndEnqueue(T *pToken); - template T *ScanToken(T *pToken); + // and the tokens + void ScanDirective(); + void ScanDocStart(); + void ScanDocEnd(); + void ScanBlockSeqStart(); + void ScanBlockMapSTart(); + void ScanBlockEnd(); + void ScanBlockEntry(); + void ScanFlowStart(); + void ScanFlowEnd(); + void ScanFlowEntry(); + void ScanKey(); + void ScanValue(); + void ScanAnchorOrAlias(); + void ScanTag(); + void ScanPlainScalar(); + void ScanQuotedScalar(); + void ScanBlockScalar(); private: // the stream @@ -55,7 +73,6 @@ namespace YAML // the output (tokens) std::queue m_tokens; - std::set m_limboTokens; // state info bool m_startedStream, m_endedStream; diff --git a/scantoken.cpp b/scantoken.cpp index f9ea4bf..6e22a88 100644 --- a/scantoken.cpp +++ b/scantoken.cpp @@ -9,36 +9,13 @@ namespace YAML /////////////////////////////////////////////////////////////////////// // Specialization for scanning specific tokens - // StreamStartToken - template <> StreamStartToken *Scanner::ScanToken(StreamStartToken *pToken) - { - m_startedStream = true; - m_simpleKeyAllowed = true; - m_indents.push(-1); - - return pToken; - } - - // StreamEndToken - template <> StreamEndToken *Scanner::ScanToken(StreamEndToken *pToken) - { - // force newline - if(INPUT.column > 0) - INPUT.column = 0; - - PopIndentTo(-1); - VerifyAllSimpleKeys(); - - m_simpleKeyAllowed = false; - m_endedStream = true; - - return pToken; - } - - // DirectiveToken + // Directive // . Note: no semantic checking is done here (that's for the parser to do) - template <> DirectiveToken *Scanner::ScanToken(DirectiveToken *pToken) + void Scanner::ScanDirective() { + std::string name; + std::vector params; + // pop indents and simple keys PopIndentTo(-1); VerifyAllSimpleKeys(); @@ -50,7 +27,7 @@ namespace YAML // read name while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT)) - pToken->name += INPUT.GetChar(); + name += INPUT.GetChar(); // read parameters while(1) { @@ -67,14 +44,17 @@ namespace YAML while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT)) param += INPUT.GetChar(); - pToken->params.push_back(param); + params.push_back(param); } - return pToken; + Token *pToken = new Token(TT_DIRECTIVE); + pToken->value = name; + pToken->params = params; + m_tokens.push(pToken); } - // DocumentStartToken - template <> DocumentStartToken *Scanner::ScanToken(DocumentStartToken *pToken) + // DocStart + void Scanner::ScanDocStart() { PopIndentTo(INPUT.column); VerifyAllSimpleKeys(); @@ -82,11 +62,11 @@ namespace YAML // eat INPUT.Eat(3); - return pToken; + m_tokens.push(new Token(TT_DOC_START)); } - // DocumentEndToken - template <> DocumentEndToken *Scanner::ScanToken(DocumentEndToken *pToken) + // DocEnd + void Scanner::ScanDocEnd() { PopIndentTo(-1); VerifyAllSimpleKeys(); @@ -94,37 +74,25 @@ namespace YAML // eat INPUT.Eat(3); - return pToken; + m_tokens.push(new Token(TT_DOC_END)); } - // FlowSeqStartToken - template <> FlowSeqStartToken *Scanner::ScanToken(FlowSeqStartToken *pToken) + // FlowStart + void Scanner::ScanFlowStart() { - // flow sequences can be simple keys + // flows can be simple keys InsertSimpleKey(); m_flowLevel++; m_simpleKeyAllowed = true; // eat - INPUT.Eat(1); - return pToken; + char ch = INPUT.GetChar(); + TOKEN_TYPE type = (ch == Keys::FlowSeqStart ? TT_FLOW_SEQ_START : TT_FLOW_MAP_START); + m_tokens.push(new Token(type)); } - // FlowMapStartToken - template <> FlowMapStartToken *Scanner::ScanToken(FlowMapStartToken *pToken) - { - // flow maps can be simple keys - InsertSimpleKey(); - m_flowLevel++; - m_simpleKeyAllowed = true; - - // eat - INPUT.Eat(1); - return pToken; - } - - // FlowSeqEndToken - template <> FlowSeqEndToken *Scanner::ScanToken(FlowSeqEndToken *pToken) + // FlowEnd + void Scanner::ScanFlowEnd() { if(m_flowLevel == 0) throw IllegalFlowEnd(); @@ -133,36 +101,23 @@ namespace YAML m_simpleKeyAllowed = false; // eat - INPUT.Eat(1); - return pToken; + char ch = INPUT.GetChar(); + TOKEN_TYPE type = (ch == Keys::FlowSeqEnd ? TT_FLOW_SEQ_END : TT_FLOW_MAP_END); + m_tokens.push(new Token(type)); } - // FlowMapEndToken - template <> FlowMapEndToken *Scanner::ScanToken(FlowMapEndToken *pToken) - { - if(m_flowLevel == 0) - throw IllegalFlowEnd(); - - m_flowLevel--; - m_simpleKeyAllowed = false; - - // eat - INPUT.Eat(1); - return pToken; - } - - // FlowEntryToken - template <> FlowEntryToken *Scanner::ScanToken(FlowEntryToken *pToken) + // FlowEntry + void Scanner::ScanFlowEntry() { m_simpleKeyAllowed = true; // eat INPUT.Eat(1); - return pToken; + m_tokens.push(new Token(TT_FLOW_ENTRY)); } - // BlockEntryToken - template <> BlockEntryToken *Scanner::ScanToken(BlockEntryToken *pToken) + // BlockEntry + void Scanner::ScanBlockEntry() { // we better be in the block context! if(m_flowLevel > 0) @@ -177,11 +132,11 @@ namespace YAML // eat INPUT.Eat(1); - return pToken; + m_tokens.push(new Token(TT_BLOCK_ENTRY)); } - // KeyToken - template <> KeyToken *Scanner::ScanToken(KeyToken *pToken) + // Key + void Scanner::ScanKey() { // handle keys diffently in the block context (and manage indents) if(m_flowLevel == 0) { @@ -199,11 +154,11 @@ namespace YAML // eat INPUT.Eat(1); - return pToken; + m_tokens.push(new Token(TT_KEY)); } - // ValueToken - template <> ValueToken *Scanner::ScanToken(ValueToken *pToken) + // Value + void Scanner::ScanValue() { // does this follow a simple key? if(m_isLastKeyValid) { @@ -227,12 +182,15 @@ namespace YAML // eat INPUT.Eat(1); - return pToken; + m_tokens.push(new Token(TT_VALUE)); } - // AnchorToken - template <> AnchorToken *Scanner::ScanToken(AnchorToken *pToken) + // AnchorOrAlias + void Scanner::ScanAnchorOrAlias() { + bool alias; + std::string tag; + // insert a potential simple key if(m_simpleKeyAllowed) InsertSimpleKey(); @@ -240,10 +198,9 @@ namespace YAML // eat the indicator char indicator = INPUT.GetChar(); - pToken->alias = (indicator == Keys::Alias); + alias = (indicator == Keys::Alias); // now eat the content - std::string tag; while(Exp::AlphaNumeric.Matches(INPUT)) tag += INPUT.GetChar(); @@ -256,13 +213,16 @@ namespace YAML throw IllegalCharacterInAnchor(); // and we're done + Token *pToken = new Token(alias ? TT_ALIAS : TT_ANCHOR); pToken->value = tag; - return pToken; + m_tokens.push(pToken); } - // TagToken - template <> TagToken *Scanner::ScanToken(TagToken *pToken) + // Tag + void Scanner::ScanTag() { + std::string handle, suffix; + // insert a potential simple key if(m_simpleKeyAllowed) InsertSimpleKey(); @@ -273,7 +233,7 @@ namespace YAML // read the handle while(INPUT.peek() != EOF && INPUT.peek() != Keys::Tag && !Exp::BlankOrBreak.Matches(INPUT)) - pToken->handle += INPUT.GetChar(); + handle += INPUT.GetChar(); // is there a suffix? if(INPUT.peek() == Keys::Tag) { @@ -282,15 +242,20 @@ namespace YAML // then read it while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT)) - pToken->suffix += INPUT.GetChar(); + suffix += INPUT.GetChar(); } - return pToken; + Token *pToken = new Token(TT_TAG); + pToken->value = handle; + pToken->params.push_back(suffix); + m_tokens.push(pToken); } - // PlainScalarToken - template <> PlainScalarToken *Scanner::ScanToken(PlainScalarToken *pToken) + // PlainScalar + void Scanner::ScanPlainScalar() { + std::string scalar; + // set up the scanning parameters ScanScalarParams params; params.end = (m_flowLevel > 0 ? Exp::EndScalarInFlow : Exp::EndScalar) || (RegEx(' ') + Exp::Comment); @@ -307,7 +272,7 @@ namespace YAML if(m_simpleKeyAllowed) InsertSimpleKey(); - pToken->value = ScanScalar(INPUT, params); + scalar = ScanScalar(INPUT, params); // can have a simple key only if we ended the scalar by starting a new line m_simpleKeyAllowed = params.leadingSpaces; @@ -317,21 +282,25 @@ namespace YAML if(Exp::IllegalColonInScalar.Matches(INPUT)) throw IllegalScalar(); - return pToken; + Token *pToken = new Token(TT_SCALAR); + pToken->value = scalar; + m_tokens.push(pToken); } - // QuotedScalarToken - template <> QuotedScalarToken *Scanner::ScanToken(QuotedScalarToken *pToken) + // QuotedScalar + void Scanner::ScanQuotedScalar() { + std::string scalar; + // eat single or double quote char quote = INPUT.GetChar(); - pToken->single = (quote == '\''); + bool single = (quote == '\''); // setup the scanning parameters ScanScalarParams params; - params.end = (pToken->single ? RegEx(quote) && !Exp::EscSingleQuote : RegEx(quote)); + params.end = (single ? RegEx(quote) && !Exp::EscSingleQuote : RegEx(quote)); params.eatEnd = true; - params.escape = (pToken->single ? '\'' : '\\'); + params.escape = (single ? '\'' : '\\'); params.indent = 0; params.fold = true; params.eatLeadingWhitespace = true; @@ -343,18 +312,22 @@ namespace YAML if(m_simpleKeyAllowed) InsertSimpleKey(); - pToken->value = ScanScalar(INPUT, params); + scalar = ScanScalar(INPUT, params); m_simpleKeyAllowed = false; - return pToken; + Token *pToken = new Token(TT_SCALAR); + pToken->value = scalar; + m_tokens.push(pToken); } // BlockScalarToken // . These need a little extra processing beforehand. // . We need to scan the line where the indicator is (this doesn't count as part of the scalar), // and then we need to figure out what level of indentation we'll be using. - template <> BlockScalarToken *Scanner::ScanToken(BlockScalarToken *pToken) + void Scanner::ScanBlockScalar() { + std::string scalar; + ScanScalarParams params; params.indent = 1; params.detectIndent = true; @@ -401,10 +374,13 @@ namespace YAML params.trimTrailingSpaces = false; params.onTabInIndentation = THROW; - pToken->value = ScanScalar(INPUT, params); + scalar = ScanScalar(INPUT, params); // simple keys always ok after block scalars (since we're gonna start a new line anyways) m_simpleKeyAllowed = true; - return pToken; + + Token *pToken = new Token(TT_SCALAR); + pToken->value = scalar; + m_tokens.push(pToken); } } diff --git a/simplekey.cpp b/simplekey.cpp index aa5d8b3..3f17265 100644 --- a/simplekey.cpp +++ b/simplekey.cpp @@ -44,7 +44,7 @@ namespace YAML // key.required = true; // TODO: is this correct? // then add the (now unverified) key - key.pKey = new KeyToken; + key.pKey = new Token(TT_KEY); key.pKey->status = TS_UNVERIFIED; m_tokens.push(key.pKey); diff --git a/token.h b/token.h index 3a3bff5..17bd20d 100644 --- a/token.h +++ b/token.h @@ -7,64 +7,61 @@ namespace YAML { enum TOKEN_STATUS { TS_VALID, TS_INVALID, TS_UNVERIFIED }; + enum TOKEN_TYPE { + TT_DIRECTIVE, + TT_DOC_START, + TT_DOC_END, + TT_BLOCK_SEQ_START, + TT_BLOCK_MAP_START, + TT_BLOCK_END, + TT_BLOCK_ENTRY, + TT_FLOW_SEQ_START, + TT_FLOW_MAP_START, + TT_FLOW_SEQ_END, + TT_FLOW_MAP_END, + TT_FLOW_ENTRY, + TT_KEY, + TT_VALUE, + TT_ANCHOR, + TT_ALIAS, + TT_TAG, + TT_SCALAR, + }; + + const std::string TokenNames[] = { + "DIRECTIVE", + "DOC_START", + "DOC_END", + "BLOCK_SEQ_START", + "BLOCK_MAP_START", + "BLOCK_END", + "BLOCK_ENTRY", + "FLOW_SEQ_START", + "FLOW_MAP_START", + "FLOW_SEQ_END", + "FLOW_MAP_END", + "FLOW_ENTRY", + "KEY", + "VALUE", + "ANCHOR", + "ALIAS", + "TAG", + "SCALAR", + }; struct Token { - Token(): status(TS_VALID) {} - virtual ~Token() {} - virtual void Write(std::ostream& out) const {} + Token(TOKEN_TYPE type_): status(TS_VALID), type(type_) {} + + friend std::ostream& operator << (std::ostream& out, const Token& token) { + out << TokenNames[token.type] << ": " << token.value; + for(unsigned i=0;i params; - - virtual void Write(std::ostream& out) const { out << name; for(unsigned i=0;i Date: Mon, 30 Jun 2008 22:34:10 +0000 Subject: [PATCH 032/295] Renamed the stream member functions get() and eat(). --- exp.cpp | 6 +-- scanner.cpp | 6 +-- scanner.h | 1 - scanscalar.cpp | 12 ++--- scantoken.cpp | 46 +++++++++---------- stream.cpp | 16 +++---- stream.h | 8 ++-- test.yaml | 121 +++++++++++++++++++++++++++++++++++++++---------- 8 files changed, 143 insertions(+), 73 deletions(-) diff --git a/exp.cpp b/exp.cpp index f2b89d5..493654c 100644 --- a/exp.cpp +++ b/exp.cpp @@ -39,7 +39,7 @@ namespace YAML // grab string std::string str; for(int i=0;i #include #include -#include "regex.h" #include "stream.h" namespace YAML diff --git a/scanscalar.cpp b/scanscalar.cpp index 9026d91..17f9d7c 100644 --- a/scanscalar.cpp +++ b/scanscalar.cpp @@ -43,7 +43,7 @@ namespace YAML // escaped newline? (only if we're escaping on slash) if(params.escape == '\\' && Exp::EscBreak.Matches(INPUT)) { int n = Exp::EscBreak.Match(INPUT); - INPUT.Eat(n); + INPUT.eat(n); continue; } @@ -54,7 +54,7 @@ namespace YAML } // otherwise, just add the damn character - scalar += INPUT.GetChar(); + scalar += INPUT.get(); } // eof? if we're looking to eat something, then we throw @@ -72,21 +72,21 @@ namespace YAML int n = params.end.Match(INPUT); if(n >= 0) { if(params.eatEnd) - INPUT.Eat(n); + INPUT.eat(n); break; } // ******************************** // Phase #2: eat line ending n = Exp::Break.Match(INPUT); - INPUT.Eat(n); + INPUT.eat(n); // ******************************** // Phase #3: scan initial spaces // first the required indentation while(INPUT.peek() == ' ' && (INPUT.column < params.indent || (params.detectIndent && !foundNonEmptyLine))) - INPUT.Eat(1); + INPUT.eat(1); // update indent if we're auto-detecting if(params.detectIndent && !foundNonEmptyLine) @@ -101,7 +101,7 @@ namespace YAML if(!params.eatLeadingWhitespace) break; - INPUT.Eat(1); + INPUT.eat(1); } // was this an empty line? diff --git a/scantoken.cpp b/scantoken.cpp index 6e22a88..fca7ae6 100644 --- a/scantoken.cpp +++ b/scantoken.cpp @@ -23,17 +23,17 @@ namespace YAML m_simpleKeyAllowed = false; // eat indicator - INPUT.Eat(1); + INPUT.eat(1); // read name while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT)) - name += INPUT.GetChar(); + name += INPUT.get(); // read parameters while(1) { // first get rid of whitespace while(Exp::Blank.Matches(INPUT)) - INPUT.Eat(1); + INPUT.eat(1); // break on newline or comment if(INPUT.peek() == EOF || Exp::Break.Matches(INPUT) || Exp::Comment.Matches(INPUT)) @@ -42,7 +42,7 @@ namespace YAML // now read parameter std::string param; while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT)) - param += INPUT.GetChar(); + param += INPUT.get(); params.push_back(param); } @@ -61,7 +61,7 @@ namespace YAML m_simpleKeyAllowed = false; // eat - INPUT.Eat(3); + INPUT.eat(3); m_tokens.push(new Token(TT_DOC_START)); } @@ -73,7 +73,7 @@ namespace YAML m_simpleKeyAllowed = false; // eat - INPUT.Eat(3); + INPUT.eat(3); m_tokens.push(new Token(TT_DOC_END)); } @@ -86,7 +86,7 @@ namespace YAML m_simpleKeyAllowed = true; // eat - char ch = INPUT.GetChar(); + char ch = INPUT.get(); TOKEN_TYPE type = (ch == Keys::FlowSeqStart ? TT_FLOW_SEQ_START : TT_FLOW_MAP_START); m_tokens.push(new Token(type)); } @@ -101,7 +101,7 @@ namespace YAML m_simpleKeyAllowed = false; // eat - char ch = INPUT.GetChar(); + char ch = INPUT.get(); TOKEN_TYPE type = (ch == Keys::FlowSeqEnd ? TT_FLOW_SEQ_END : TT_FLOW_MAP_END); m_tokens.push(new Token(type)); } @@ -112,7 +112,7 @@ namespace YAML m_simpleKeyAllowed = true; // eat - INPUT.Eat(1); + INPUT.eat(1); m_tokens.push(new Token(TT_FLOW_ENTRY)); } @@ -131,7 +131,7 @@ namespace YAML m_simpleKeyAllowed = true; // eat - INPUT.Eat(1); + INPUT.eat(1); m_tokens.push(new Token(TT_BLOCK_ENTRY)); } @@ -153,7 +153,7 @@ namespace YAML m_simpleKeyAllowed = false; // eat - INPUT.Eat(1); + INPUT.eat(1); m_tokens.push(new Token(TT_KEY)); } @@ -181,7 +181,7 @@ namespace YAML } // eat - INPUT.Eat(1); + INPUT.eat(1); m_tokens.push(new Token(TT_VALUE)); } @@ -197,12 +197,12 @@ namespace YAML m_simpleKeyAllowed = false; // eat the indicator - char indicator = INPUT.GetChar(); + char indicator = INPUT.get(); alias = (indicator == Keys::Alias); // now eat the content while(Exp::AlphaNumeric.Matches(INPUT)) - tag += INPUT.GetChar(); + tag += INPUT.get(); // we need to have read SOMETHING! if(tag.empty()) @@ -229,20 +229,20 @@ namespace YAML m_simpleKeyAllowed = false; // eat the indicator - INPUT.Eat(1); + INPUT.eat(1); // read the handle while(INPUT.peek() != EOF && INPUT.peek() != Keys::Tag && !Exp::BlankOrBreak.Matches(INPUT)) - handle += INPUT.GetChar(); + handle += INPUT.get(); // is there a suffix? if(INPUT.peek() == Keys::Tag) { // eat the indicator - INPUT.Eat(1); + INPUT.eat(1); // then read it while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT)) - suffix += INPUT.GetChar(); + suffix += INPUT.get(); } Token *pToken = new Token(TT_TAG); @@ -293,7 +293,7 @@ namespace YAML std::string scalar; // eat single or double quote - char quote = INPUT.GetChar(); + char quote = INPUT.get(); bool single = (quote == '\''); // setup the scanning parameters @@ -333,13 +333,13 @@ namespace YAML params.detectIndent = true; // eat block indicator ('|' or '>') - char indicator = INPUT.GetChar(); + char indicator = INPUT.get(); params.fold = (indicator == Keys::FoldedScalar); // eat chomping/indentation indicators int n = Exp::Chomp.Match(INPUT); for(int i=0;i Date: Mon, 30 Jun 2008 23:57:58 +0000 Subject: [PATCH 033/295] Finished parsing of basic data types (scalar, sequence, map). --- content.h | 7 +++ document.cpp | 34 +++++++++++++ document.h | 6 +++ main.cpp | 10 ++-- map.cpp | 104 +++++++++++++++++++++++++++++++++++++++ map.h | 7 +++ node.cpp | 62 +++++++++++++++++++++++ node.h | 6 +++ parser.cpp | 20 ++------ parser.h | 5 +- reader.cpp | 21 -------- reader.h | 21 -------- scalar.cpp | 21 +++++++- scalar.h | 5 +- scanner.cpp | 14 ++++++ scanner.h | 2 + sequence.cpp | 77 +++++++++++++++++++++++++++++ sequence.h | 8 +++ test.yaml | 105 ++++----------------------------------- yaml-reader.vcproj | 120 ++++++++++++++++++++++----------------------- 20 files changed, 434 insertions(+), 221 deletions(-) delete mode 100644 reader.cpp delete mode 100644 reader.h diff --git a/content.h b/content.h index d251bb1..12a2b86 100644 --- a/content.h +++ b/content.h @@ -1,13 +1,20 @@ #pragma once +#include + namespace YAML { + class Scanner; + class Content { public: Content(); virtual ~Content(); + virtual void Parse(Scanner *pScanner) = 0; + virtual void Write(std::ostream& out, int indent) = 0; + protected: }; } diff --git a/document.cpp b/document.cpp index 74286e9..fd526e2 100644 --- a/document.cpp +++ b/document.cpp @@ -1,5 +1,7 @@ #include "document.h" #include "node.h" +#include "token.h" +#include "scanner.h" namespace YAML { @@ -17,4 +19,36 @@ namespace YAML delete m_pRoot; m_pRoot = 0; } + + void Document::Parse(Scanner *pScanner) + { + Clear(); + + // we better have some tokens in the queue + if(!pScanner->PeekNextToken()) + return; + + // first eat doc start (optional) + if(pScanner->PeekNextToken()->type == TT_DOC_START) + pScanner->EatNextToken(); + + // now create our root node and parse it + m_pRoot = new Node; + m_pRoot->Parse(pScanner); + + // and finally eat any doc ends we see + while(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_DOC_END) + pScanner->EatNextToken(); + } + + std::ostream& operator << (std::ostream& out, const Document& doc) + { + if(!doc.m_pRoot) { + out << "{empty node}\n"; + return out; + } + + doc.m_pRoot->Write(out, 0); + return out; + } } diff --git a/document.h b/document.h index 62be716..e018981 100644 --- a/document.h +++ b/document.h @@ -1,8 +1,11 @@ #pragma once +#include + namespace YAML { class Node; + class Scanner; class Document { @@ -11,6 +14,9 @@ namespace YAML ~Document(); void Clear(); + void Parse(Scanner *pScanner); + + friend std::ostream& operator << (std::ostream& out, const Document& doc); private: Node *m_pRoot; diff --git a/main.cpp b/main.cpp index 2a8898a..dba870d 100644 --- a/main.cpp +++ b/main.cpp @@ -1,12 +1,16 @@ -#include "reader.h" +#include "parser.h" #include +#include int main() { std::ifstream fin("test.yaml"); - YAML::Reader reader(fin); + YAML::Parser parser(fin); + YAML::Document doc; - reader.GetNextDocument(doc); + parser.GetNextDocument(doc); + std::cout << doc; + getchar(); return 0; } \ No newline at end of file diff --git a/map.cpp b/map.cpp index 882ad15..ef93d35 100644 --- a/map.cpp +++ b/map.cpp @@ -1,5 +1,7 @@ #include "map.h" #include "node.h" +#include "scanner.h" +#include "token.h" namespace YAML { @@ -14,4 +16,106 @@ namespace YAML delete it->second; } } + + void Map::Parse(Scanner *pScanner) + { + // grab start token + Token *pToken = pScanner->GetNextToken(); + + switch(pToken->type) { + case TT_BLOCK_MAP_START: ParseBlock(pScanner); break; + case TT_FLOW_MAP_START: ParseFlow(pScanner); break; + } + + delete pToken; + } + + void Map::ParseBlock(Scanner *pScanner) + { + while(1) { + Token *pToken = pScanner->PeekNextToken(); + if(!pToken) + break; // TODO: throw? + + if(pToken->type != TT_KEY && pToken->type != TT_BLOCK_END) + break; // TODO: throw? + + pScanner->PopNextToken(); + if(pToken->type == TT_BLOCK_END) + break; + + Node *pKey = new Node; + Node *pValue = new Node; + m_data[pKey] = pValue; + + // grab key + pKey->Parse(pScanner); + + // now grab value (optional) + if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { + pScanner->PopNextToken(); + pValue->Parse(pScanner); + } + } + } + + void Map::ParseFlow(Scanner *pScanner) + { + while(1) { + Token *pToken = pScanner->PeekNextToken(); + if(!pToken) + break; // TODO: throw? + + // first check for end + if(pToken->type == TT_FLOW_MAP_END) { + pScanner->EatNextToken(); + break; + } + + // now it better be a key + if(pToken->type != TT_KEY) + break; // TODO: throw? + + pScanner->PopNextToken(); + + Node *pKey = new Node; + Node *pValue = new Node; + m_data[pKey] = pValue; + + // grab key + pKey->Parse(pScanner); + + // now grab value (optional) + if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { + pScanner->PopNextToken(); + pValue->Parse(pScanner); + } + + // now eat the separator (or could be a map end, which we ignore - but if it's neither, then it's a bad node) + pToken = pScanner->PeekNextToken(); + if(pToken->type == TT_FLOW_ENTRY) + pScanner->EatNextToken(); + else if(pToken->type != TT_FLOW_MAP_END) + break; // TODO: throw? + } + } + + void Map::Write(std::ostream& out, int indent) + { + for(int i=0;ifirst->Write(out, indent + 2); + + for(int i=0;isecond->Write(out, indent + 2); + } + } } diff --git a/map.h b/map.h index b165ac5..391d3f2 100644 --- a/map.h +++ b/map.h @@ -13,6 +13,13 @@ namespace YAML Map(); virtual ~Map(); + virtual void Parse(Scanner *pScanner); + virtual void Write(std::ostream& out, int indent); + + private: + void ParseBlock(Scanner *pScanner); + void ParseFlow(Scanner *pScanner); + protected: typedef std::map node_map; node_map m_data; diff --git a/node.cpp b/node.cpp index c3ca6a4..844f045 100644 --- a/node.cpp +++ b/node.cpp @@ -1,8 +1,11 @@ #include "node.h" +#include "token.h" +#include "scanner.h" #include "content.h" #include "parser.h" #include "scalar.h" #include "sequence.h" +#include "map.h" namespace YAML { @@ -20,4 +23,63 @@ namespace YAML delete m_pContent; m_pContent = 0; } + + void Node::Parse(Scanner *pScanner) + { + ParseHeader(pScanner); + + // now split based on what kind of node we should be + Token *pToken = pScanner->PeekNextToken(); + if(pToken->type == TT_DOC_END) + return; + + switch(pToken->type) { + case TT_SCALAR: + m_pContent = new Scalar; + m_pContent->Parse(pScanner); + break; + case TT_FLOW_SEQ_START: + case TT_BLOCK_SEQ_START: + case TT_BLOCK_ENTRY: + m_pContent = new Sequence; + m_pContent->Parse(pScanner); + break; + case TT_FLOW_MAP_START: + case TT_BLOCK_MAP_START: + m_pContent = new Map; + m_pContent->Parse(pScanner); + } + } + + // ParseHeader + // . Grabs any tag, alias, or anchor tokens and deals with them. + void Node::ParseHeader(Scanner *pScanner) + { + while(1) { + Token *pToken = pScanner->PeekNextToken(); + if(!pToken || pToken->type != TT_TAG || pToken->type != TT_ANCHOR || pToken->type != TT_ALIAS) + break; + + pScanner->PopNextToken(); + switch(pToken->type) { + case TT_TAG: + break; + case TT_ANCHOR: + break; + case TT_ALIAS: + break; + } + delete pToken; + } + } + + void Node::Write(std::ostream& out, int indent) + { + if(!m_pContent) { + for(int i=0;iWrite(out, indent); + } } diff --git a/node.h b/node.h index b553faa..ab15fbf 100644 --- a/node.h +++ b/node.h @@ -10,6 +10,7 @@ namespace YAML const std::string MapTag = "!!map"; class Content; + class Scanner; class Node { @@ -18,6 +19,11 @@ namespace YAML ~Node(); void Clear(); + void Parse(Scanner *pScanner); + void Write(std::ostream& out, int indent); + + private: + void ParseHeader(Scanner *pScanner); private: std::string m_tag; diff --git a/parser.cpp b/parser.cpp index 75c014c..4b4411d 100644 --- a/parser.cpp +++ b/parser.cpp @@ -1,30 +1,20 @@ #include "parser.h" -#include "node.h" -#include "token.h" - -#include +#include "scanner.h" namespace YAML { - Parser::Parser(std::istream& in): m_scanner(in) + Parser::Parser(std::istream& in): m_pScanner(0) { + m_pScanner = new Scanner(in); } Parser::~Parser() { + delete m_pScanner; } void Parser::GetNextDocument(Document& document) { - // scan and output, for now - while(1) { - Token *pToken = m_scanner.GetNextToken(); - if(!pToken) - break; - - std::cout << *pToken << std::endl; - delete pToken; - } - getchar(); + document.Parse(m_pScanner); } } diff --git a/parser.h b/parser.h index 6b4602b..4f19852 100644 --- a/parser.h +++ b/parser.h @@ -1,13 +1,12 @@ #pragma once #include -#include -#include "scanner.h" #include "document.h" namespace YAML { class Node; + class Scanner; class Parser { @@ -18,6 +17,6 @@ namespace YAML void GetNextDocument(Document& document); private: - Scanner m_scanner; + Scanner *m_pScanner; }; } diff --git a/reader.cpp b/reader.cpp deleted file mode 100644 index 4d94459..0000000 --- a/reader.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "reader.h" -#include "scanner.h" -#include "parser.h" - -namespace YAML -{ - Reader::Reader(std::istream& in): m_pParser(0) - { - m_pParser = new Parser(in); - } - - Reader::~Reader() - { - delete m_pParser; - } - - void Reader::GetNextDocument(Document& document) - { - m_pParser->GetNextDocument(document); - } -} diff --git a/reader.h b/reader.h deleted file mode 100644 index 3226af9..0000000 --- a/reader.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include -#include "document.h" - -namespace YAML -{ - class Parser; - - class Reader - { - public: - Reader(std::istream& in); - ~Reader(); - - void GetNextDocument(Document& document); - - private: - Parser *m_pParser; - }; -} diff --git a/scalar.cpp b/scalar.cpp index 4552194..9fe73a6 100644 --- a/scalar.cpp +++ b/scalar.cpp @@ -1,12 +1,31 @@ #include "scalar.h" +#include "scanner.h" +#include "token.h" namespace YAML { - Scalar::Scalar(const std::string& data): m_data(data) + Scalar::Scalar() { } Scalar::~Scalar() { } + + void Scalar::Parse(Scanner *pScanner) + { + Token *pToken = pScanner->GetNextToken(); + m_data = pToken->value; + delete pToken; + } + + void Scalar::Write(std::ostream& out, int indent) + { + for(int i=0;iGetNextToken(); + + switch(pToken->type) { + case TT_BLOCK_SEQ_START: ParseBlock(pScanner); break; + case TT_BLOCK_ENTRY: ParseImplicit(pScanner); break; + case TT_FLOW_SEQ_START: ParseFlow(pScanner); break; + } + + delete pToken; + } + + void Sequence::ParseBlock(Scanner *pScanner) + { + while(1) { + Token *pToken = pScanner->PeekNextToken(); + if(!pToken) + break; // TODO: throw? + + if(pToken->type != TT_BLOCK_ENTRY && pToken->type != TT_BLOCK_END) + break; // TODO: throw? + + pScanner->PopNextToken(); + if(pToken->type == TT_BLOCK_END) + break; + + Node *pNode = new Node; + m_data.push_back(pNode); + pNode->Parse(pScanner); + } + } + + void Sequence::ParseImplicit(Scanner *pScanner) + { + // TODO + } + + void Sequence::ParseFlow(Scanner *pScanner) + { + while(1) { + Token *pToken = pScanner->PeekNextToken(); + if(!pToken) + break; // TODO: throw? + + // first check for end + if(pToken->type == TT_FLOW_SEQ_END) { + pScanner->PopNextToken(); + break; + } + + // then read the node + Node *pNode = new Node; + m_data.push_back(pNode); + pNode->Parse(pScanner); + + // now eat the separator (or could be a sequence end, which we ignore - but if it's neither, then it's a bad node) + pToken = pScanner->PeekNextToken(); + if(pToken->type == TT_FLOW_ENTRY) + pScanner->EatNextToken(); + else if(pToken->type != TT_FLOW_SEQ_END) + break; // TODO: throw? + } + } + + void Sequence::Write(std::ostream& out, int indent) + { + for(int i=0;iWrite(out, indent + 1); + } } diff --git a/sequence.h b/sequence.h index cf7d1dd..928f53c 100644 --- a/sequence.h +++ b/sequence.h @@ -13,6 +13,14 @@ namespace YAML Sequence(); virtual ~Sequence(); + virtual void Parse(Scanner *pScanner); + virtual void Write(std::ostream& out, int indent); + + private: + void ParseBlock(Scanner *pScanner); + void ParseImplicit(Scanner *pScanner); + void ParseFlow(Scanner *pScanner); + protected: std::vector m_data; }; diff --git a/test.yaml b/test.yaml index 8a9714c..1840d58 100644 --- a/test.yaml +++ b/test.yaml @@ -1,97 +1,10 @@ --- -model: - file: data/models/compound.model - textures: data/materials/compound -rooms: - - name: "Room #1" - pos: [0, 0, 0] - size: [1000, 1000, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [24, 24] - map: | - ----------------------- - -+++++++++++++++++++++- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+--------------------- - -+--------------------- - -+--------------------- - -+--------------------- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+++++++++++++++++++++- - ----------------------- - - name: Doorway - pos: [1000, 400, 0] - size: [50, 200, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [5, 9] - map: | - ----- - -+++- - ----- - ----- - ----- - ----- - ----- - -+++- - ----- - - name: "Room #2" - pos: [1050, 0, 0] - size: [1000, 1000, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [24, 24] - map: | - ----------------------- - -+++++++++++++++++++++- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - ---------------------+- - ---------------------+- - ---------------------+- - ---------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+++++++++++++++++++++- - ----------------------- -exits: - - room1: "Room #1" - room2: "Room #2" - dir: e - pos: [400, 600] +here's a sequence: + - item 1 + - item 2 +now an inline sequence: [1, 2, 3] +and here's a map: + name: Jesse + age: 23 +and here's an inline map: {state: Illinois, city: Urbana-Champaign} +... \ No newline at end of file diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index 46a4707..4f8d382 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -161,38 +161,10 @@ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > - - - - - - - - - - - - - - @@ -233,48 +205,44 @@ > + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - @@ -298,6 +266,10 @@ RelativePath=".\stream.h" > + + + + + + + + + + + + + + + + Date: Tue, 1 Jul 2008 01:17:10 +0000 Subject: [PATCH 034/295] Added parsing of anchors, aliases, and tags (still no semantics yet). Fixed a silly bug in the simple key pushing (queues are FIFO!). --- map.cpp | 20 +++++++++++--- map.h | 1 + node.cpp | 75 ++++++++++++++++++++++++++++++++++++++++++++-------- node.h | 6 ++++- parser.cpp | 13 +++++++++ parser.h | 1 + scanner.cpp | 8 +++--- sequence.cpp | 37 ++++++++++++++++++++++---- sequence.h | 1 + test.yaml | 39 ++++++++++++++++++++------- 10 files changed, 167 insertions(+), 34 deletions(-) diff --git a/map.cpp b/map.cpp index ef93d35..d3cba8f 100644 --- a/map.cpp +++ b/map.cpp @@ -10,28 +10,37 @@ namespace YAML } Map::~Map() + { + Clear(); + } + + void Map::Clear() { for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) { delete it->first; delete it->second; } + m_data.clear(); } void Map::Parse(Scanner *pScanner) { - // grab start token - Token *pToken = pScanner->GetNextToken(); + Clear(); + + // split based on start token + Token *pToken = pScanner->PeekNextToken(); switch(pToken->type) { case TT_BLOCK_MAP_START: ParseBlock(pScanner); break; case TT_FLOW_MAP_START: ParseFlow(pScanner); break; } - - delete pToken; } void Map::ParseBlock(Scanner *pScanner) { + // eat start token + pScanner->EatNextToken(); + while(1) { Token *pToken = pScanner->PeekNextToken(); if(!pToken) @@ -61,6 +70,9 @@ namespace YAML void Map::ParseFlow(Scanner *pScanner) { + // eat start token + pScanner->EatNextToken(); + while(1) { Token *pToken = pScanner->PeekNextToken(); if(!pToken) diff --git a/map.h b/map.h index 391d3f2..0da12b3 100644 --- a/map.h +++ b/map.h @@ -13,6 +13,7 @@ namespace YAML Map(); virtual ~Map(); + void Clear(); virtual void Parse(Scanner *pScanner); virtual void Write(std::ostream& out, int indent); diff --git a/node.cpp b/node.cpp index 844f045..439bdd6 100644 --- a/node.cpp +++ b/node.cpp @@ -9,7 +9,7 @@ namespace YAML { - Node::Node(): m_pContent(0) + Node::Node(): m_pContent(0), m_alias(false) { } @@ -22,12 +22,19 @@ namespace YAML { delete m_pContent; m_pContent = 0; + m_alias = false; } void Node::Parse(Scanner *pScanner) { + Clear(); + ParseHeader(pScanner); + // is this an alias? if so, it can have no content + if(m_alias) + return; + // now split based on what kind of node we should be Token *pToken = pScanner->PeekNextToken(); if(pToken->type == TT_DOC_END) @@ -57,29 +64,75 @@ namespace YAML { while(1) { Token *pToken = pScanner->PeekNextToken(); - if(!pToken || pToken->type != TT_TAG || pToken->type != TT_ANCHOR || pToken->type != TT_ALIAS) + if(!pToken || (pToken->type != TT_TAG && pToken->type != TT_ANCHOR && pToken->type != TT_ALIAS)) break; - pScanner->PopNextToken(); switch(pToken->type) { - case TT_TAG: - break; - case TT_ANCHOR: - break; - case TT_ALIAS: - break; + case TT_TAG: ParseTag(pScanner); break; + case TT_ANCHOR: ParseAnchor(pScanner); break; + case TT_ALIAS: ParseAlias(pScanner); break; } - delete pToken; } } + void Node::ParseTag(Scanner *pScanner) + { + if(m_tag != "") + return; // TODO: throw + + Token *pToken = pScanner->PeekNextToken(); + m_tag = pToken->value; + for(unsigned i=0;iparams.size();i++) + m_tag += pToken->params[i]; + pScanner->PopNextToken(); + } + + void Node::ParseAnchor(Scanner *pScanner) + { + if(m_anchor != "") + return; // TODO: throw + + Token *pToken = pScanner->PeekNextToken(); + m_anchor = pToken->value; + m_alias = false; + pScanner->PopNextToken(); + } + + void Node::ParseAlias(Scanner *pScanner) + { + if(m_anchor != "") + return; // TODO: throw + if(m_tag != "") + return; // TODO: throw (aliases can't have any content, *including* tags) + + Token *pToken = pScanner->PeekNextToken(); + m_anchor = pToken->value; + m_alias = true; + pScanner->PopNextToken(); + } + void Node::Write(std::ostream& out, int indent) { + if(m_tag != "") { + for(int i=0;iWrite(out, indent); + } } } diff --git a/node.h b/node.h index ab15fbf..d6e8727 100644 --- a/node.h +++ b/node.h @@ -24,9 +24,13 @@ namespace YAML private: void ParseHeader(Scanner *pScanner); + void ParseTag(Scanner *pScanner); + void ParseAnchor(Scanner *pScanner); + void ParseAlias(Scanner *pScanner); private: - std::string m_tag; + bool m_alias; + std::string m_anchor, m_tag; Content *m_pContent; }; } diff --git a/parser.cpp b/parser.cpp index 4b4411d..8db28ea 100644 --- a/parser.cpp +++ b/parser.cpp @@ -1,5 +1,7 @@ #include "parser.h" #include "scanner.h" +#include "token.h" +#include namespace YAML { @@ -17,4 +19,15 @@ namespace YAML { document.Parse(m_pScanner); } + + void Parser::PrintTokens() + { + while(1) { + Token *pToken = m_pScanner->GetNextToken(); + if(!pToken) + break; + + std::cout << *pToken << std::endl; + } + } } diff --git a/parser.h b/parser.h index 4f19852..95bb663 100644 --- a/parser.h +++ b/parser.h @@ -15,6 +15,7 @@ namespace YAML ~Parser(); void GetNextDocument(Document& document); + void PrintTokens(); private: Scanner *m_pScanner; diff --git a/scanner.cpp b/scanner.cpp index d44ec7c..a231b9d 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -254,12 +254,14 @@ namespace YAML // now push m_indents.push(column); + Token *pToken = 0; if(sequence) - m_tokens.push(new Token(TT_BLOCK_SEQ_START)); + pToken = new Token(TT_BLOCK_SEQ_START); else - m_tokens.push(new Token(TT_BLOCK_MAP_START)); + pToken = new Token(TT_BLOCK_MAP_START); - return m_tokens.front(); + m_tokens.push(pToken); + return pToken; } // PopIndentTo diff --git a/sequence.cpp b/sequence.cpp index df4a178..8332e13 100644 --- a/sequence.cpp +++ b/sequence.cpp @@ -11,27 +11,36 @@ namespace YAML } Sequence::~Sequence() + { + Clear(); + } + + void Sequence::Clear() { for(unsigned i=0;iGetNextToken(); + Clear(); + + // split based on start token + Token *pToken = pScanner->PeekNextToken(); switch(pToken->type) { case TT_BLOCK_SEQ_START: ParseBlock(pScanner); break; case TT_BLOCK_ENTRY: ParseImplicit(pScanner); break; case TT_FLOW_SEQ_START: ParseFlow(pScanner); break; } - - delete pToken; } void Sequence::ParseBlock(Scanner *pScanner) { + // eat start token + pScanner->EatNextToken(); + while(1) { Token *pToken = pScanner->PeekNextToken(); if(!pToken) @@ -52,11 +61,29 @@ namespace YAML void Sequence::ParseImplicit(Scanner *pScanner) { - // TODO + while(1) { + Token *pToken = pScanner->PeekNextToken(); + // we're actually *allowed* to have no tokens at some point + if(!pToken) + break; + + // and we end at anything other than a block entry + if(pToken->type != TT_BLOCK_ENTRY) + break; + + pScanner->PopNextToken(); + + Node *pNode = new Node; + m_data.push_back(pNode); + pNode->Parse(pScanner); + } } void Sequence::ParseFlow(Scanner *pScanner) { + // eat start token + pScanner->EatNextToken(); + while(1) { Token *pToken = pScanner->PeekNextToken(); if(!pToken) diff --git a/sequence.h b/sequence.h index 928f53c..42e9fbb 100644 --- a/sequence.h +++ b/sequence.h @@ -13,6 +13,7 @@ namespace YAML Sequence(); virtual ~Sequence(); + void Clear(); virtual void Parse(Scanner *pScanner); virtual void Write(std::ostream& out, int indent); diff --git a/test.yaml b/test.yaml index 1840d58..4b98eea 100644 --- a/test.yaml +++ b/test.yaml @@ -1,10 +1,29 @@ ---- -here's a sequence: - - item 1 - - item 2 -now an inline sequence: [1, 2, 3] -and here's a map: - name: Jesse - age: 23 -and here's an inline map: {state: Illinois, city: Urbana-Champaign} -... \ No newline at end of file +--- ! +invoice: 34843 +date : 2001-01-23 +bill-to: &id001 + given : Chris + family : Dumars + address: + lines: | + 458 Walkman Dr. + Suite #292 + city : Royal Oak + state : MI + postal : 48046 +ship-to: *id001 +product: + - sku : BL394D + quantity : 4 + description : Basketball + price : 450.00 + - sku : BL4438H + quantity : 1 + description : Super Hoop + price : 2392.00 +tax : 251.42 +total: 4443.52 +comments: + Late afternoon is best. + Backup contact is Nancy + Billsmer @ 338-4338. \ No newline at end of file From 8eb50fe9d0c99a85caf3fa9a8282eae2ebaa6407 Mon Sep 17 00:00:00 2001 From: beder Date: Tue, 1 Jul 2008 06:28:10 +0000 Subject: [PATCH 035/295] Tags, anchors, and aliases are all parsed now. --- content.h | 4 +- document.cpp | 4 +- document.h | 3 +- main.cpp | 7 ++- map.cpp | 18 +++---- map.h | 6 +-- node.cpp | 27 +++++----- node.h | 11 ++-- parser.cpp | 74 ++++++++++++++++++++++++-- parser.h | 15 +++++- parserstate.cpp | 25 +++++++++ parserstate.h | 20 +++++++ scalar.cpp | 2 +- scalar.h | 2 +- scantoken.cpp | 16 +++--- sequence.cpp | 20 +++---- sequence.h | 8 +-- test.yaml | 126 ++++++++++++++++++++++++++++++++++----------- yaml-reader.vcproj | 8 +++ 19 files changed, 303 insertions(+), 93 deletions(-) create mode 100644 parserstate.cpp create mode 100644 parserstate.h diff --git a/content.h b/content.h index 12a2b86..ce23447 100644 --- a/content.h +++ b/content.h @@ -1,10 +1,12 @@ #pragma once #include +#include "parserstate.h" namespace YAML { class Scanner; + class Parser; class Content { @@ -12,7 +14,7 @@ namespace YAML Content(); virtual ~Content(); - virtual void Parse(Scanner *pScanner) = 0; + virtual void Parse(Scanner *pScanner, const ParserState& state) = 0; virtual void Write(std::ostream& out, int indent) = 0; protected: diff --git a/document.cpp b/document.cpp index fd526e2..c5d1996 100644 --- a/document.cpp +++ b/document.cpp @@ -20,7 +20,7 @@ namespace YAML m_pRoot = 0; } - void Document::Parse(Scanner *pScanner) + void Document::Parse(Scanner *pScanner, const ParserState& state) { Clear(); @@ -34,7 +34,7 @@ namespace YAML // now create our root node and parse it m_pRoot = new Node; - m_pRoot->Parse(pScanner); + m_pRoot->Parse(pScanner, state); // and finally eat any doc ends we see while(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_DOC_END) diff --git a/document.h b/document.h index e018981..257f570 100644 --- a/document.h +++ b/document.h @@ -1,6 +1,7 @@ #pragma once #include +#include "parserstate.h" namespace YAML { @@ -14,7 +15,7 @@ namespace YAML ~Document(); void Clear(); - void Parse(Scanner *pScanner); + void Parse(Scanner *pScanner, const ParserState& state); friend std::ostream& operator << (std::ostream& out, const Document& doc); diff --git a/main.cpp b/main.cpp index dba870d..22d0b1b 100644 --- a/main.cpp +++ b/main.cpp @@ -8,8 +8,11 @@ int main() YAML::Parser parser(fin); YAML::Document doc; - parser.GetNextDocument(doc); - std::cout << doc; + while(parser) { + std::cout << "---\n"; + parser.GetNextDocument(doc); + std::cout << doc; + } getchar(); return 0; diff --git a/map.cpp b/map.cpp index d3cba8f..e759f37 100644 --- a/map.cpp +++ b/map.cpp @@ -23,7 +23,7 @@ namespace YAML m_data.clear(); } - void Map::Parse(Scanner *pScanner) + void Map::Parse(Scanner *pScanner, const ParserState& state) { Clear(); @@ -31,12 +31,12 @@ namespace YAML Token *pToken = pScanner->PeekNextToken(); switch(pToken->type) { - case TT_BLOCK_MAP_START: ParseBlock(pScanner); break; - case TT_FLOW_MAP_START: ParseFlow(pScanner); break; + case TT_BLOCK_MAP_START: ParseBlock(pScanner, state); break; + case TT_FLOW_MAP_START: ParseFlow(pScanner, state); break; } } - void Map::ParseBlock(Scanner *pScanner) + void Map::ParseBlock(Scanner *pScanner, const ParserState& state) { // eat start token pScanner->EatNextToken(); @@ -58,17 +58,17 @@ namespace YAML m_data[pKey] = pValue; // grab key - pKey->Parse(pScanner); + pKey->Parse(pScanner, state); // now grab value (optional) if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { pScanner->PopNextToken(); - pValue->Parse(pScanner); + pValue->Parse(pScanner, state); } } } - void Map::ParseFlow(Scanner *pScanner) + void Map::ParseFlow(Scanner *pScanner, const ParserState& state) { // eat start token pScanner->EatNextToken(); @@ -95,12 +95,12 @@ namespace YAML m_data[pKey] = pValue; // grab key - pKey->Parse(pScanner); + pKey->Parse(pScanner, state); // now grab value (optional) if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { pScanner->PopNextToken(); - pValue->Parse(pScanner); + 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) diff --git a/map.h b/map.h index 0da12b3..9f29298 100644 --- a/map.h +++ b/map.h @@ -14,12 +14,12 @@ namespace YAML virtual ~Map(); void Clear(); - virtual void Parse(Scanner *pScanner); + virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent); private: - void ParseBlock(Scanner *pScanner); - void ParseFlow(Scanner *pScanner); + void ParseBlock(Scanner *pScanner, const ParserState& state); + void ParseFlow(Scanner *pScanner, const ParserState& state); protected: typedef std::map node_map; diff --git a/node.cpp b/node.cpp index 439bdd6..47e2080 100644 --- a/node.cpp +++ b/node.cpp @@ -25,11 +25,11 @@ namespace YAML m_alias = false; } - void Node::Parse(Scanner *pScanner) + void Node::Parse(Scanner *pScanner, const ParserState& state) { Clear(); - ParseHeader(pScanner); + ParseHeader(pScanner, state); // is this an alias? if so, it can have no content if(m_alias) @@ -43,24 +43,24 @@ namespace YAML switch(pToken->type) { case TT_SCALAR: m_pContent = new Scalar; - m_pContent->Parse(pScanner); + m_pContent->Parse(pScanner, state); break; case TT_FLOW_SEQ_START: case TT_BLOCK_SEQ_START: case TT_BLOCK_ENTRY: m_pContent = new Sequence; - m_pContent->Parse(pScanner); + m_pContent->Parse(pScanner, state); break; case TT_FLOW_MAP_START: case TT_BLOCK_MAP_START: m_pContent = new Map; - m_pContent->Parse(pScanner); + m_pContent->Parse(pScanner, state); } } // ParseHeader // . Grabs any tag, alias, or anchor tokens and deals with them. - void Node::ParseHeader(Scanner *pScanner) + void Node::ParseHeader(Scanner *pScanner, const ParserState& state) { while(1) { Token *pToken = pScanner->PeekNextToken(); @@ -68,26 +68,27 @@ namespace YAML break; switch(pToken->type) { - case TT_TAG: ParseTag(pScanner); break; - case TT_ANCHOR: ParseAnchor(pScanner); break; - case TT_ALIAS: ParseAlias(pScanner); break; + case TT_TAG: ParseTag(pScanner, state); break; + case TT_ANCHOR: ParseAnchor(pScanner, state); break; + case TT_ALIAS: ParseAlias(pScanner, state); break; } } } - void Node::ParseTag(Scanner *pScanner) + void Node::ParseTag(Scanner *pScanner, const ParserState& state) { if(m_tag != "") return; // TODO: throw Token *pToken = pScanner->PeekNextToken(); - m_tag = pToken->value; + m_tag = state.TranslateTag(pToken->value); + for(unsigned i=0;iparams.size();i++) m_tag += pToken->params[i]; pScanner->PopNextToken(); } - void Node::ParseAnchor(Scanner *pScanner) + void Node::ParseAnchor(Scanner *pScanner, const ParserState& state) { if(m_anchor != "") return; // TODO: throw @@ -98,7 +99,7 @@ namespace YAML pScanner->PopNextToken(); } - void Node::ParseAlias(Scanner *pScanner) + void Node::ParseAlias(Scanner *pScanner, const ParserState& state) { if(m_anchor != "") return; // TODO: throw diff --git a/node.h b/node.h index d6e8727..f8cfe5c 100644 --- a/node.h +++ b/node.h @@ -2,6 +2,7 @@ #include #include +#include "parserstate.h" namespace YAML { @@ -19,14 +20,14 @@ namespace YAML ~Node(); void Clear(); - void Parse(Scanner *pScanner); + void Parse(Scanner *pScanner, const ParserState& state); void Write(std::ostream& out, int indent); private: - void ParseHeader(Scanner *pScanner); - void ParseTag(Scanner *pScanner); - void ParseAnchor(Scanner *pScanner); - void ParseAlias(Scanner *pScanner); + void ParseHeader(Scanner *pScanner, const ParserState& state); + void ParseTag(Scanner *pScanner, const ParserState& state); + void ParseAnchor(Scanner *pScanner, const ParserState& state); + void ParseAlias(Scanner *pScanner, const ParserState& state); private: bool m_alias; diff --git a/parser.cpp b/parser.cpp index 8db28ea..053c83e 100644 --- a/parser.cpp +++ b/parser.cpp @@ -1,13 +1,14 @@ #include "parser.h" #include "scanner.h" #include "token.h" -#include +#include namespace YAML { Parser::Parser(std::istream& in): m_pScanner(0) { m_pScanner = new Scanner(in); + m_state.Reset(); } Parser::~Parser() @@ -15,19 +16,82 @@ namespace YAML delete m_pScanner; } - void Parser::GetNextDocument(Document& document) + Parser::operator bool() const { - document.Parse(m_pScanner); + return m_pScanner->PeekNextToken() != 0; } - void Parser::PrintTokens() + void Parser::GetNextDocument(Document& document) + { + // first read directives + ParseDirectives(); + + // then parse the document + document.Parse(m_pScanner, m_state); + } + + void Parser::ParseDirectives() + { + bool readDirective = false; + + while(1) { + Token *pToken = m_pScanner->PeekNextToken(); + if(!pToken || pToken->type != TT_DIRECTIVE) + break; + + // 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_state.Reset(); + + readDirective = true; + HandleDirective(pToken->value, pToken->params); + m_pScanner->PopNextToken(); + } + } + + void Parser::HandleDirective(const std::string& name, const std::vector & params) + { + if(name == "YAML") + HandleYamlDirective(params); + else if(name == "TAG") + HandleTagDirective(params); + } + + // HandleYamlDirective + // . Should be of the form 'major.minor' (like a version number) + void Parser::HandleYamlDirective(const std::vector & params) + { + if(params.empty()) + return; // TODO: throw? (or throw on params.size() > 1?) + + std::stringstream str(params[0]); + str >> m_state.version.major; + str.get(); + str >> m_state.version.minor; + if(!str) + return; // TODO: throw? (or throw if there are any more characters in the stream?) + + // TODO: throw on major > 1? warning on major == 1, minor > 1? + } + + void Parser::HandleTagDirective(const std::vector & params) + { + if(params.size() != 2) + return; // TODO: throw? + + std::string handle = params[0], prefix = params[1]; + m_state.tags[handle] = prefix; + } + + void Parser::PrintTokens(std::ostream& out) { while(1) { Token *pToken = m_pScanner->GetNextToken(); if(!pToken) break; - std::cout << *pToken << std::endl; + out << *pToken << std::endl; } } } diff --git a/parser.h b/parser.h index 95bb663..cd42017 100644 --- a/parser.h +++ b/parser.h @@ -1,7 +1,11 @@ #pragma once #include +#include +#include +#include #include "document.h" +#include "parserstate.h" namespace YAML { @@ -14,10 +18,19 @@ namespace YAML Parser(std::istream& in); ~Parser(); + operator bool() const; + void GetNextDocument(Document& document); - void PrintTokens(); + void PrintTokens(std::ostream& out); + + private: + void ParseDirectives(); + void HandleDirective(const std::string& name, const std::vector & params); + void HandleYamlDirective(const std::vector & params); + void HandleTagDirective(const std::vector & params); private: Scanner *m_pScanner; + ParserState m_state; }; } diff --git a/parserstate.cpp b/parserstate.cpp new file mode 100644 index 0000000..d0b5209 --- /dev/null +++ b/parserstate.cpp @@ -0,0 +1,25 @@ +#include "parserstate.h" + +namespace YAML +{ + void ParserState::Reset() + { + // version + version.major = 1; + version.minor = 1; + + // and tags + tags.clear(); + tags["!"] = "!"; + tags["!!"] = "tag:yaml.org,2002:"; + } + + std::string ParserState::TranslateTag(const std::string& handle) const + { + std::map ::const_iterator it = tags.find(handle); + if(it == tags.end()) + return handle; + + return it->second; + } +} diff --git a/parserstate.h b/parserstate.h new file mode 100644 index 0000000..e98667d --- /dev/null +++ b/parserstate.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +namespace YAML +{ + struct Version { + int major, minor; + }; + + struct ParserState + { + Version version; + std::map tags; + + void Reset(); + std::string TranslateTag(const std::string& handle) const; + }; +} diff --git a/scalar.cpp b/scalar.cpp index 9fe73a6..5176e52 100644 --- a/scalar.cpp +++ b/scalar.cpp @@ -12,7 +12,7 @@ namespace YAML { } - void Scalar::Parse(Scanner *pScanner) + void Scalar::Parse(Scanner *pScanner, const ParserState& state) { Token *pToken = pScanner->GetNextToken(); m_data = pToken->value; diff --git a/scalar.h b/scalar.h index bea56af..90f2583 100644 --- a/scalar.h +++ b/scalar.h @@ -11,7 +11,7 @@ namespace YAML Scalar(); virtual ~Scalar(); - virtual void Parse(Scanner *pScanner); + virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent); protected: diff --git a/scantoken.cpp b/scantoken.cpp index fca7ae6..05bae3d 100644 --- a/scantoken.cpp +++ b/scantoken.cpp @@ -189,7 +189,7 @@ namespace YAML void Scanner::ScanAnchorOrAlias() { bool alias; - std::string tag; + std::string name; // insert a potential simple key if(m_simpleKeyAllowed) @@ -202,10 +202,10 @@ namespace YAML // now eat the content while(Exp::AlphaNumeric.Matches(INPUT)) - tag += INPUT.get(); + name += INPUT.get(); // we need to have read SOMETHING! - if(tag.empty()) + if(name.empty()) throw AnchorNotFound(); // and needs to end correctly @@ -214,7 +214,7 @@ namespace YAML // and we're done Token *pToken = new Token(alias ? TT_ALIAS : TT_ANCHOR); - pToken->value = tag; + pToken->value = name; m_tokens.push(pToken); } @@ -229,7 +229,7 @@ namespace YAML m_simpleKeyAllowed = false; // eat the indicator - INPUT.eat(1); + handle += INPUT.get(); // read the handle while(INPUT.peek() != EOF && INPUT.peek() != Keys::Tag && !Exp::BlankOrBreak.Matches(INPUT)) @@ -238,11 +238,15 @@ namespace YAML // is there a suffix? if(INPUT.peek() == Keys::Tag) { // eat the indicator - INPUT.eat(1); + handle += INPUT.get(); // then read it while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT)) suffix += INPUT.get(); + } else { + // this is a bit weird: we keep just the '!' as the handle and move the rest to the suffix + suffix = handle.substr(1); + handle = "!"; } Token *pToken = new Token(TT_TAG); diff --git a/sequence.cpp b/sequence.cpp index 8332e13..8d0ca13 100644 --- a/sequence.cpp +++ b/sequence.cpp @@ -22,7 +22,7 @@ namespace YAML m_data.clear(); } - void Sequence::Parse(Scanner *pScanner) + void Sequence::Parse(Scanner *pScanner, const ParserState& state) { Clear(); @@ -30,13 +30,13 @@ namespace YAML Token *pToken = pScanner->PeekNextToken(); switch(pToken->type) { - case TT_BLOCK_SEQ_START: ParseBlock(pScanner); break; - case TT_BLOCK_ENTRY: ParseImplicit(pScanner); break; - case TT_FLOW_SEQ_START: ParseFlow(pScanner); break; + case TT_BLOCK_SEQ_START: ParseBlock(pScanner, state); break; + case TT_BLOCK_ENTRY: ParseImplicit(pScanner, state); break; + case TT_FLOW_SEQ_START: ParseFlow(pScanner, state); break; } } - void Sequence::ParseBlock(Scanner *pScanner) + void Sequence::ParseBlock(Scanner *pScanner, const ParserState& state) { // eat start token pScanner->EatNextToken(); @@ -55,11 +55,11 @@ namespace YAML Node *pNode = new Node; m_data.push_back(pNode); - pNode->Parse(pScanner); + pNode->Parse(pScanner, state); } } - void Sequence::ParseImplicit(Scanner *pScanner) + void Sequence::ParseImplicit(Scanner *pScanner, const ParserState& state) { while(1) { Token *pToken = pScanner->PeekNextToken(); @@ -75,11 +75,11 @@ namespace YAML Node *pNode = new Node; m_data.push_back(pNode); - pNode->Parse(pScanner); + pNode->Parse(pScanner, state); } } - void Sequence::ParseFlow(Scanner *pScanner) + void Sequence::ParseFlow(Scanner *pScanner, const ParserState& state) { // eat start token pScanner->EatNextToken(); @@ -98,7 +98,7 @@ namespace YAML // then read the node Node *pNode = new Node; m_data.push_back(pNode); - pNode->Parse(pScanner); + 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) pToken = pScanner->PeekNextToken(); diff --git a/sequence.h b/sequence.h index 42e9fbb..85fcf8a 100644 --- a/sequence.h +++ b/sequence.h @@ -14,13 +14,13 @@ namespace YAML virtual ~Sequence(); void Clear(); - virtual void Parse(Scanner *pScanner); + virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent); private: - void ParseBlock(Scanner *pScanner); - void ParseImplicit(Scanner *pScanner); - void ParseFlow(Scanner *pScanner); + void ParseBlock(Scanner *pScanner, const ParserState& state); + void ParseImplicit(Scanner *pScanner, const ParserState& state); + void ParseFlow(Scanner *pScanner, const ParserState& state); protected: std::vector m_data; diff --git a/test.yaml b/test.yaml index 4b98eea..8a9714c 100644 --- a/test.yaml +++ b/test.yaml @@ -1,29 +1,97 @@ ---- ! -invoice: 34843 -date : 2001-01-23 -bill-to: &id001 - given : Chris - family : Dumars - address: - lines: | - 458 Walkman Dr. - Suite #292 - city : Royal Oak - state : MI - postal : 48046 -ship-to: *id001 -product: - - sku : BL394D - quantity : 4 - description : Basketball - price : 450.00 - - sku : BL4438H - quantity : 1 - description : Super Hoop - price : 2392.00 -tax : 251.42 -total: 4443.52 -comments: - Late afternoon is best. - Backup contact is Nancy - Billsmer @ 338-4338. \ No newline at end of file +--- +model: + file: data/models/compound.model + textures: data/materials/compound +rooms: + - name: "Room #1" + pos: [0, 0, 0] + size: [1000, 1000, 500] + height: 500 + stairtype: none + display: [] + pathfinding: + tilesize: 50 + size: [24, 24] + map: | + ----------------------- + -+++++++++++++++++++++- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+--------------------- + -+--------------------- + -+--------------------- + -+--------------------- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+++++++++++++++++++++- + ----------------------- + - name: Doorway + pos: [1000, 400, 0] + size: [50, 200, 500] + height: 500 + stairtype: none + display: [] + pathfinding: + tilesize: 50 + size: [5, 9] + map: | + ----- + -+++- + ----- + ----- + ----- + ----- + ----- + -+++- + ----- + - name: "Room #2" + pos: [1050, 0, 0] + size: [1000, 1000, 500] + height: 500 + stairtype: none + display: [] + pathfinding: + tilesize: 50 + size: [24, 24] + map: | + ----------------------- + -+++++++++++++++++++++- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + ---------------------+- + ---------------------+- + ---------------------+- + ---------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+++++++++++++++++++++- + ----------------------- +exits: + - room1: "Room #1" + room2: "Room #2" + dir: e + pos: [400, 600] diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index 4f8d382..62387b0 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -204,6 +204,10 @@ RelativePath=".\parser.cpp" > + + + + Date: Tue, 1 Jul 2008 06:34:55 +0000 Subject: [PATCH 036/295] Fixed opening newline bug for block scalars. --- scanscalar.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/scanscalar.cpp b/scanscalar.cpp index 17f9d7c..5c41cc3 100644 --- a/scanscalar.cpp +++ b/scanscalar.cpp @@ -18,7 +18,7 @@ namespace YAML // and different places in the above flow. std::string ScanScalar(Stream& INPUT, ScanScalarParams& params) { - bool foundNonEmptyLine = false; + bool foundNonEmptyLine = false, pastOpeningBreak = false; bool emptyLine = false, moreIndented = false; std::string scalar; params.leadingSpaces = false; @@ -39,6 +39,7 @@ namespace YAML } foundNonEmptyLine = true; + pastOpeningBreak = true; // escaped newline? (only if we're escaping on slash) if(params.escape == '\\' && Exp::EscBreak.Matches(INPUT)) { @@ -108,15 +109,17 @@ namespace YAML bool nextEmptyLine = Exp::Break.Matches(INPUT); bool nextMoreIndented = (INPUT.peek() == ' '); - // TODO: for block scalars, we always start with a newline, so we should fold OR keep that - - if(params.fold && !emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented) - scalar += " "; - else - scalar += "\n"; + // for block scalars, we always start with a newline, so we should ignore it (not fold or keep) + if(pastOpeningBreak) { + if(params.fold && !emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented) + scalar += " "; + else + scalar += "\n"; + } emptyLine = nextEmptyLine; moreIndented = nextMoreIndented; + pastOpeningBreak = true; // are we done via indentation? if(!emptyLine && INPUT.column < params.indent) { From b4b287c4e9758b7355b5f8d9c86dd037830b9f99 Mon Sep 17 00:00:00 2001 From: beder Date: Wed, 2 Jul 2008 01:22:39 +0000 Subject: [PATCH 037/295] Added an iterator class that can iterate through both sequence and map nodes. --- content.h | 18 ++++++++ document.cpp | 9 ++++ document.h | 1 + exceptions.h | 6 +++ iterator.cpp | 73 ++++++++++++++++++++++++++++++++ main.cpp | 31 +++++++++++--- map.cpp | 12 ++++++ map.h | 2 + node.cpp | 95 +++++++++++++++++++++++++++++++++++++++++ node.h | 65 ++++++++++++++++++++++++++-- scalar.cpp | 55 ++++++++++++++++++++++++ scalar.h | 9 ++++ sequence.cpp | 12 ++++++ sequence.h | 3 ++ test.yaml | 103 +++------------------------------------------ yaml-reader.vcproj | 4 ++ 16 files changed, 393 insertions(+), 105 deletions(-) create mode 100644 iterator.cpp diff --git a/content.h b/content.h index ce23447..525a10a 100644 --- a/content.h +++ b/content.h @@ -1,12 +1,16 @@ #pragma once #include +#include +#include #include "parserstate.h" +#include "exceptions.h" namespace YAML { class Scanner; class Parser; + class Node; class Content { @@ -17,6 +21,20 @@ namespace YAML virtual void Parse(Scanner *pScanner, const ParserState& state) = 0; virtual void Write(std::ostream& out, int indent) = 0; + virtual bool GetBegin(std::vector ::const_iterator& it) { return false; } + virtual bool GetBegin(std::map ::const_iterator& it) { return false; } + virtual bool GetEnd(std::vector ::const_iterator& it) { return false; } + virtual bool GetEnd(std::map ::const_iterator& it) { return false; } + + // extraction + virtual void Read(std::string& s) { throw InvalidScalar(); } + virtual void Read(int& i) { throw InvalidScalar(); } + virtual void Read(unsigned& u) { throw InvalidScalar(); } + virtual void Read(long& l) { throw InvalidScalar(); } + virtual void Read(float& f) { throw InvalidScalar(); } + virtual void Read(double& d) { throw InvalidScalar(); } + virtual void Read(char& c) { throw InvalidScalar(); } + protected: }; } diff --git a/document.cpp b/document.cpp index c5d1996..8d4d55f 100644 --- a/document.cpp +++ b/document.cpp @@ -41,8 +41,17 @@ namespace YAML pScanner->EatNextToken(); } + const Node& Document::GetRoot() const + { + if(!m_pRoot) + throw; + + return *m_pRoot; + } + std::ostream& operator << (std::ostream& out, const Document& doc) { + out << "---\n"; if(!doc.m_pRoot) { out << "{empty node}\n"; return out; diff --git a/document.h b/document.h index 257f570..3517cf0 100644 --- a/document.h +++ b/document.h @@ -16,6 +16,7 @@ namespace YAML void Clear(); void Parse(Scanner *pScanner, const ParserState& state); + const Node& GetRoot() const; friend std::ostream& operator << (std::ostream& out, const Document& doc); diff --git a/exceptions.h b/exceptions.h index 9c5df62..2998d08 100644 --- a/exceptions.h +++ b/exceptions.h @@ -6,7 +6,9 @@ namespace YAML { class Exception: public std::exception {}; class ScannerException: public Exception {}; + class RepresentationException: public Exception {}; + // scanner exceptions class UnknownToken: public ScannerException {}; class IllegalBlockEntry: public ScannerException {}; class IllegalMapKey: public ScannerException {}; @@ -37,4 +39,8 @@ namespace YAML InvalidUnicode(unsigned value_): value(value_) {} unsigned value; }; + + // representation exceptions + class InvalidScalar: public RepresentationException {}; + class BadDereference: public RepresentationException {}; } diff --git a/iterator.cpp b/iterator.cpp new file mode 100644 index 0000000..074e5ee --- /dev/null +++ b/iterator.cpp @@ -0,0 +1,73 @@ +#include "node.h" +#include "exceptions.h" + +namespace YAML +{ + Node::Iterator::Iterator(): type(IT_NONE) + { + } + + Node::Iterator::Iterator(std::vector ::const_iterator it): seqIter(it), type(IT_SEQ) + { + } + + Node::Iterator::Iterator(std::map ::const_iterator it): mapIter(it), type(IT_MAP) + { + } + + Node::Iterator::~Iterator() + { + } + + Node::Iterator& Node::Iterator::operator ++ () + { + if(type == IT_SEQ) + ++seqIter; + else if(type == IT_MAP) + ++mapIter; + + return *this; + } + + const Node& Node::Iterator::operator * () + { + if(type == IT_SEQ) + return **seqIter; + + throw BadDereference(); + } + + const Node& Node::Iterator::first() + { + if(type == IT_MAP) + return *mapIter->first; + + throw BadDereference(); + } + + const Node& Node::Iterator::second() + { + if(type == IT_MAP) + return *mapIter->second; + + throw BadDereference(); + } + + bool operator == (const Node::Iterator& it, const Node::Iterator& jt) + { + if(it.type != jt.type) + return false; + + if(it.type == Node::Iterator::IT_SEQ) + return it.seqIter == jt.seqIter; + else if(it.type == Node::Iterator::IT_MAP) + return it.mapIter == jt.mapIter; + + return true; + } + + bool operator != (const Node::Iterator& it, const Node::Iterator& jt) + { + return !(it == jt); + } +} diff --git a/main.cpp b/main.cpp index 22d0b1b..12de0fb 100644 --- a/main.cpp +++ b/main.cpp @@ -1,18 +1,39 @@ #include "parser.h" +#include "node.h" +#include "exceptions.h" #include #include int main() { std::ifstream fin("test.yaml"); - YAML::Parser parser(fin); - YAML::Document doc; - while(parser) { - std::cout << "---\n"; + try { + YAML::Parser parser(fin); + if(!parser) + return 0; + + YAML::Document doc; parser.GetNextDocument(doc); - std::cout << doc; + + const YAML::Node& root = doc.GetRoot(); + for(YAML::Node::Iterator it=root.begin();it!=root.end();++it) { + std::string name; + (*it)["name"] >> name; + std::cout << "Name: " << name << std::endl; + + int age; + (*it)["age"] >> age; + std::cout << "Age: " << age << std::endl; + + std::string school; + (*it)["school"] >> school; + std::cout << "School: " << school << std::endl; + } + } catch(YAML::Exception& e) { + std::cout << "Error parsing the yaml!\n"; } + getchar(); return 0; diff --git a/map.cpp b/map.cpp index e759f37..6cc511c 100644 --- a/map.cpp +++ b/map.cpp @@ -23,6 +23,18 @@ namespace YAML m_data.clear(); } + bool Map::GetBegin(std::map ::const_iterator& it) + { + it = m_data.begin(); + return true; + } + + bool Map::GetEnd(std::map ::const_iterator& it) + { + it = m_data.end(); + return true; + } + void Map::Parse(Scanner *pScanner, const ParserState& state) { Clear(); diff --git a/map.h b/map.h index 9f29298..bceb705 100644 --- a/map.h +++ b/map.h @@ -14,6 +14,8 @@ namespace YAML virtual ~Map(); void Clear(); + virtual bool GetBegin(std::map ::const_iterator& it); + virtual bool GetEnd(std::map ::const_iterator& it); virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent); diff --git a/node.cpp b/node.cpp index 47e2080..4f9e7d9 100644 --- a/node.cpp +++ b/node.cpp @@ -136,4 +136,99 @@ namespace YAML m_pContent->Write(out, indent); } } + + // begin + // Returns an iterator to the beginning of this (sequence or map). + Node::Iterator Node::begin() const + { + if(!m_pContent) + return Iterator(); + + std::vector ::const_iterator seqIter; + if(m_pContent->GetBegin(seqIter)) + return Iterator(seqIter); + + std::map ::const_iterator mapIter; + if(m_pContent->GetBegin(mapIter)) + return Iterator(mapIter); + + return Iterator(); + } + + // end + // . Returns an iterator to the end of this (sequence or map). + Node::Iterator Node::end() const + { + if(!m_pContent) + return Iterator(); + + std::vector ::const_iterator seqIter; + if(m_pContent->GetEnd(seqIter)) + return Iterator(seqIter); + + std::map ::const_iterator mapIter; + if(m_pContent->GetEnd(mapIter)) + return Iterator(mapIter); + + return Iterator(); + } + + /////////////////////////////////////////////////////// + // Extraction + + void operator >> (const Node& node, std::string& s) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(s); + } + + void operator >> (const Node& node, int& i) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(i); + } + + void operator >> (const Node& node, unsigned& u) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(u); + } + + void operator >> (const Node& node, long& l) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(l); + } + + void operator >> (const Node& node, float& f) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(f); + } + + void operator >> (const Node& node, double& d) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(d); + } + + void operator >> (const Node& node, char& c) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(c); + } } diff --git a/node.h b/node.h index f8cfe5c..bbfcfe9 100644 --- a/node.h +++ b/node.h @@ -2,19 +2,42 @@ #include #include +#include +#include #include "parserstate.h" +#include "exceptions.h" namespace YAML { - const std::string StrTag = "!!str"; - const std::string SeqTag = "!!seq"; - const std::string MapTag = "!!map"; - class Content; class Scanner; class Node { + public: + class Iterator + { + public: + Iterator(); + Iterator(std::vector ::const_iterator it); + Iterator(std::map ::const_iterator it); + ~Iterator(); + + friend bool operator == (const Iterator& it, const Iterator& jt); + friend bool operator != (const Iterator& it, const Iterator& jt); + Iterator& operator ++ (); + const Node& operator * (); + const Node& first(); + const Node& second(); + + private: + enum ITER_TYPE { IT_NONE, IT_SEQ, IT_MAP }; + ITER_TYPE type; + + std::vector ::const_iterator seqIter; + std::map ::const_iterator mapIter; + }; + public: Node(); ~Node(); @@ -23,6 +46,40 @@ namespace YAML void Parse(Scanner *pScanner, const ParserState& state); void Write(std::ostream& out, int indent); + Iterator begin() const; + Iterator end() const; + + template + const Node& operator [] (const T& key) const { + if(!m_pContent) + throw BadDereference(); + + for(Iterator it=begin();it!=end();++it) { + T t; + try { + it.first() >> t; + if(key == t) + return it.second(); + } catch(InvalidScalar&) { + } + } + + throw BadDereference(); + } + + const Node& operator [] (const char *key) const { + return operator [] (std::string(key)); + } + + // extraction + friend void operator >> (const Node& node, std::string& s); + friend void operator >> (const Node& node, int& i); + friend void operator >> (const Node& node, unsigned& u); + friend void operator >> (const Node& node, long& l); + friend void operator >> (const Node& node, float& f); + friend void operator >> (const Node& node, double& d); + friend void operator >> (const Node& node, char& c); + private: void ParseHeader(Scanner *pScanner, const ParserState& state); void ParseTag(Scanner *pScanner, const ParserState& state); diff --git a/scalar.cpp b/scalar.cpp index 5176e52..c33ae32 100644 --- a/scalar.cpp +++ b/scalar.cpp @@ -1,6 +1,8 @@ #include "scalar.h" #include "scanner.h" #include "token.h" +#include "exceptions.h" +#include namespace YAML { @@ -28,4 +30,57 @@ namespace YAML out << " "; out << m_data << std::endl; } + + void Scalar::Read(std::string& s) + { + s = m_data; + } + + void Scalar::Read(int& i) + { + std::stringstream data(m_data); + data >> i; + if(!data) + throw InvalidScalar(); + } + + void Scalar::Read(unsigned& u) + { + std::stringstream data(m_data); + data >> u; + if(!data) + throw InvalidScalar(); + } + + void Scalar::Read(long& l) + { + std::stringstream data(m_data); + data >> l; + if(!data) + throw InvalidScalar(); + } + + void Scalar::Read(float& f) + { + std::stringstream data(m_data); + data >> f; + if(!data) + throw InvalidScalar(); + } + + void Scalar::Read(double& d) + { + std::stringstream data(m_data); + data >> d; + if(!data) + throw InvalidScalar(); + } + + void Scalar::Read(char& c) + { + std::stringstream data(m_data); + data >> c; + if(!data) + throw InvalidScalar(); + } } diff --git a/scalar.h b/scalar.h index 90f2583..42c733c 100644 --- a/scalar.h +++ b/scalar.h @@ -14,6 +14,15 @@ namespace YAML virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent); + // extraction + virtual void Read(std::string& s); + virtual void Read(int& i); + virtual void Read(unsigned& u); + virtual void Read(long& l); + virtual void Read(float& f); + virtual void Read(double& d); + virtual void Read(char& c); + protected: std::string m_data; }; diff --git a/sequence.cpp b/sequence.cpp index 8d0ca13..16acfa4 100644 --- a/sequence.cpp +++ b/sequence.cpp @@ -22,6 +22,18 @@ namespace YAML m_data.clear(); } + bool Sequence::GetBegin(std::vector ::const_iterator& it) + { + it = m_data.begin(); + return true; + } + + bool Sequence::GetEnd(std::vector ::const_iterator& it) + { + it = m_data.end(); + return true; + } + void Sequence::Parse(Scanner *pScanner, const ParserState& state) { Clear(); diff --git a/sequence.h b/sequence.h index 85fcf8a..3897112 100644 --- a/sequence.h +++ b/sequence.h @@ -14,6 +14,9 @@ namespace YAML virtual ~Sequence(); void Clear(); + virtual bool GetBegin(std::vector ::const_iterator& it); + virtual bool GetEnd(std::vector ::const_iterator& it); + virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent); diff --git a/test.yaml b/test.yaml index 8a9714c..340878e 100644 --- a/test.yaml +++ b/test.yaml @@ -1,97 +1,8 @@ --- -model: - file: data/models/compound.model - textures: data/materials/compound -rooms: - - name: "Room #1" - pos: [0, 0, 0] - size: [1000, 1000, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [24, 24] - map: | - ----------------------- - -+++++++++++++++++++++- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+--------------------- - -+--------------------- - -+--------------------- - -+--------------------- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+++++++++++++++++++++- - ----------------------- - - name: Doorway - pos: [1000, 400, 0] - size: [50, 200, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [5, 9] - map: | - ----- - -+++- - ----- - ----- - ----- - ----- - ----- - -+++- - ----- - - name: "Room #2" - pos: [1050, 0, 0] - size: [1000, 1000, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [24, 24] - map: | - ----------------------- - -+++++++++++++++++++++- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - ---------------------+- - ---------------------+- - ---------------------+- - ---------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+++++++++++++++++++++- - ----------------------- -exits: - - room1: "Room #1" - room2: "Room #2" - dir: e - pos: [400, 600] +- name: Jesse + age: 23 + school: University of Illinois +- name: Naftali + age: 21 + school: Rhode Island School of Design +... \ No newline at end of file diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index 62387b0..4e74139 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -220,6 +220,10 @@ RelativePath=".\document.cpp" > + + From 807045bc143c8814a389a6b301080824bfb2ec3c Mon Sep 17 00:00:00 2001 From: beder Date: Wed, 2 Jul 2008 01:32:19 +0000 Subject: [PATCH 038/295] Overloaded the iterator's -> operator. --- iterator.cpp | 8 ++++++++ main.cpp | 18 +++++++----------- node.h | 1 + test.yaml | 8 ++------ 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/iterator.cpp b/iterator.cpp index 074e5ee..a9161cd 100644 --- a/iterator.cpp +++ b/iterator.cpp @@ -37,6 +37,14 @@ namespace YAML throw BadDereference(); } + const Node *Node::Iterator::operator -> () + { + if(type == IT_SEQ) + return &**seqIter; + + throw BadDereference(); + } + const Node& Node::Iterator::first() { if(type == IT_MAP) diff --git a/main.cpp b/main.cpp index 12de0fb..3639503 100644 --- a/main.cpp +++ b/main.cpp @@ -18,17 +18,13 @@ int main() const YAML::Node& root = doc.GetRoot(); for(YAML::Node::Iterator it=root.begin();it!=root.end();++it) { - std::string name; - (*it)["name"] >> name; - std::cout << "Name: " << name << std::endl; - - int age; - (*it)["age"] >> age; - std::cout << "Age: " << age << std::endl; - - std::string school; - (*it)["school"] >> school; - std::cout << "School: " << school << std::endl; + std::cout << "Sequence:"; + for(YAML::Node::Iterator jt=it->begin();jt!=it->end();++jt) { + int value; + *jt >> value; + std::cout << " " << value; + } + std::cout << std::endl; } } catch(YAML::Exception& e) { std::cout << "Error parsing the yaml!\n"; diff --git a/node.h b/node.h index bbfcfe9..dc2d603 100644 --- a/node.h +++ b/node.h @@ -27,6 +27,7 @@ namespace YAML friend bool operator != (const Iterator& it, const Iterator& jt); Iterator& operator ++ (); const Node& operator * (); + const Node *operator -> (); const Node& first(); const Node& second(); diff --git a/test.yaml b/test.yaml index 340878e..f189741 100644 --- a/test.yaml +++ b/test.yaml @@ -1,8 +1,4 @@ --- -- name: Jesse - age: 23 - school: University of Illinois -- name: Naftali - age: 21 - school: Rhode Island School of Design +- [1, 2, 3] +- [2, 4, 6] ... \ No newline at end of file From 620c322df5e6fdcd58a08413e30353b7c6ff6b42 Mon Sep 17 00:00:00 2001 From: beder Date: Wed, 2 Jul 2008 05:00:32 +0000 Subject: [PATCH 039/295] Added some parser exceptions. --- exceptions.h | 7 ++++ iterator.cpp | 12 ++++++ main.cpp | 78 ++++++++++++++++++++++++++++++++------ map.cpp | 11 +++--- node.h | 3 +- parser.cpp | 11 +++--- parserstate.cpp | 2 +- sequence.cpp | 8 ++-- test.yaml | 99 +++++++++++++++++++++++++++++++++++++++++++++++-- 9 files changed, 201 insertions(+), 30 deletions(-) diff --git a/exceptions.h b/exceptions.h index 2998d08..585963b 100644 --- a/exceptions.h +++ b/exceptions.h @@ -6,6 +6,7 @@ namespace YAML { class Exception: public std::exception {}; class ScannerException: public Exception {}; + class ParserException: public Exception {}; class RepresentationException: public Exception {}; // scanner exceptions @@ -40,6 +41,12 @@ namespace YAML unsigned value; }; + // parser exceptions + class MapEndNotFound: public ParserException {}; + class SeqEndNotFound: public ParserException {}; + class BadYAMLDirective: public ParserException {}; + class BadTAGDirective: public ParserException {}; + // representation exceptions class InvalidScalar: public RepresentationException {}; class BadDereference: public RepresentationException {}; diff --git a/iterator.cpp b/iterator.cpp index a9161cd..67d050d 100644 --- a/iterator.cpp +++ b/iterator.cpp @@ -29,6 +29,18 @@ namespace YAML return *this; } + Node::Iterator Node::Iterator::operator ++ (int) + { + Iterator temp = *this; + + if(type == IT_SEQ) + ++seqIter; + else if(type == IT_MAP) + ++mapIter; + + return temp; + } + const Node& Node::Iterator::operator * () { if(type == IT_SEQ) diff --git a/main.cpp b/main.cpp index 3639503..3b0fd88 100644 --- a/main.cpp +++ b/main.cpp @@ -1,9 +1,71 @@ #include "parser.h" #include "node.h" -#include "exceptions.h" #include #include +struct Vec3 { + float x, y, z; + + friend std::ostream& operator << (std::ostream& out, const Vec3& v) { + out << v.x << " " << v.y << " " << v.z; + return out; + } +}; + +void operator >> (const YAML::Node& node, Vec3& v) +{ + YAML::Node::Iterator it = node.begin(); + *it >> v.x; + ++it; + *it >> v.y; + ++it; + *it >> v.z; +} + +struct Room { + std::string name; + Vec3 pos, size; + float height; + + friend std::ostream& operator << (std::ostream& out, const Room& room) { + out << "Name: " << room.name << std::endl; + out << "Pos: " << room.pos << std::endl; + out << "Size: " << room.size << std::endl; + out << "Height: " << room.height << std::endl; + return out; + } +}; + +void operator >> (const YAML::Node& node, Room& room) +{ + node["name"] >> room.name; + node["pos"] >> room.pos; + node["size"] >> room.size; + node["height"] >> room.height; +} + +struct Level { + std::vector rooms; + + friend std::ostream& operator << (std::ostream& out, const Level& level) { + for(unsigned i=0;i> (const YAML::Node& node, Level& level) +{ + const YAML::Node& rooms = node["rooms"]; + for(YAML::Node::Iterator it=rooms.begin();it!=rooms.end();++it) { + Room room; + *it >> room; + level.rooms.push_back(room); + } +} + int main() { std::ifstream fin("test.yaml"); @@ -17,16 +79,10 @@ int main() parser.GetNextDocument(doc); const YAML::Node& root = doc.GetRoot(); - for(YAML::Node::Iterator it=root.begin();it!=root.end();++it) { - std::cout << "Sequence:"; - for(YAML::Node::Iterator jt=it->begin();jt!=it->end();++jt) { - int value; - *jt >> value; - std::cout << " " << value; - } - std::cout << std::endl; - } - } catch(YAML::Exception& e) { + Level level; + root >> level; + std::cout << level; + } catch(YAML::Exception&) { std::cout << "Error parsing the yaml!\n"; } diff --git a/map.cpp b/map.cpp index 6cc511c..a6da682 100644 --- a/map.cpp +++ b/map.cpp @@ -2,6 +2,7 @@ #include "node.h" #include "scanner.h" #include "token.h" +#include "exceptions.h" namespace YAML { @@ -56,10 +57,10 @@ namespace YAML while(1) { Token *pToken = pScanner->PeekNextToken(); if(!pToken) - break; // TODO: throw? + throw MapEndNotFound(); if(pToken->type != TT_KEY && pToken->type != TT_BLOCK_END) - break; // TODO: throw? + throw MapEndNotFound(); pScanner->PopNextToken(); if(pToken->type == TT_BLOCK_END) @@ -88,7 +89,7 @@ namespace YAML while(1) { Token *pToken = pScanner->PeekNextToken(); if(!pToken) - break; // TODO: throw? + throw MapEndNotFound(); // first check for end if(pToken->type == TT_FLOW_MAP_END) { @@ -98,7 +99,7 @@ namespace YAML // now it better be a key if(pToken->type != TT_KEY) - break; // TODO: throw? + throw MapEndNotFound(); pScanner->PopNextToken(); @@ -120,7 +121,7 @@ namespace YAML if(pToken->type == TT_FLOW_ENTRY) pScanner->EatNextToken(); else if(pToken->type != TT_FLOW_MAP_END) - break; // TODO: throw? + throw MapEndNotFound(); } } diff --git a/node.h b/node.h index dc2d603..8a76c71 100644 --- a/node.h +++ b/node.h @@ -26,6 +26,7 @@ namespace YAML friend bool operator == (const Iterator& it, const Iterator& jt); friend bool operator != (const Iterator& it, const Iterator& jt); Iterator& operator ++ (); + Iterator operator ++ (int); const Node& operator * (); const Node *operator -> (); const Node& first(); @@ -61,7 +62,7 @@ namespace YAML it.first() >> t; if(key == t) return it.second(); - } catch(InvalidScalar&) { + } catch(RepresentationException&) { } } diff --git a/parser.cpp b/parser.cpp index 053c83e..7b42d43 100644 --- a/parser.cpp +++ b/parser.cpp @@ -1,6 +1,7 @@ #include "parser.h" #include "scanner.h" #include "token.h" +#include "exceptions.h" #include namespace YAML @@ -62,23 +63,23 @@ namespace YAML // . Should be of the form 'major.minor' (like a version number) void Parser::HandleYamlDirective(const std::vector & params) { - if(params.empty()) - return; // TODO: throw? (or throw on params.size() > 1?) + if(params.size() != 1) + throw BadYAMLDirective(); std::stringstream str(params[0]); str >> m_state.version.major; str.get(); str >> m_state.version.minor; if(!str) - return; // TODO: throw? (or throw if there are any more characters in the stream?) + throw BadYAMLDirective(); // TODO: or throw if there are any more characters in the stream? - // TODO: throw on major > 1? warning on major == 1, minor > 1? + // TODO: throw on major > 1? warning on major == 1, minor > 2? } void Parser::HandleTagDirective(const std::vector & params) { if(params.size() != 2) - return; // TODO: throw? + throw BadTAGDirective(); std::string handle = params[0], prefix = params[1]; m_state.tags[handle] = prefix; diff --git a/parserstate.cpp b/parserstate.cpp index d0b5209..d99b970 100644 --- a/parserstate.cpp +++ b/parserstate.cpp @@ -6,7 +6,7 @@ namespace YAML { // version version.major = 1; - version.minor = 1; + version.minor = 2; // and tags tags.clear(); diff --git a/sequence.cpp b/sequence.cpp index 16acfa4..40dc3e0 100644 --- a/sequence.cpp +++ b/sequence.cpp @@ -56,10 +56,10 @@ namespace YAML while(1) { Token *pToken = pScanner->PeekNextToken(); if(!pToken) - break; // TODO: throw? + throw SeqEndNotFound(); if(pToken->type != TT_BLOCK_ENTRY && pToken->type != TT_BLOCK_END) - break; // TODO: throw? + throw SeqEndNotFound(); pScanner->PopNextToken(); if(pToken->type == TT_BLOCK_END) @@ -99,7 +99,7 @@ namespace YAML while(1) { Token *pToken = pScanner->PeekNextToken(); if(!pToken) - break; // TODO: throw? + throw SeqEndNotFound(); // first check for end if(pToken->type == TT_FLOW_SEQ_END) { @@ -117,7 +117,7 @@ namespace YAML if(pToken->type == TT_FLOW_ENTRY) pScanner->EatNextToken(); else if(pToken->type != TT_FLOW_SEQ_END) - break; // TODO: throw? + throw SeqEndNotFound(); } } diff --git a/test.yaml b/test.yaml index f189741..8a9714c 100644 --- a/test.yaml +++ b/test.yaml @@ -1,4 +1,97 @@ --- -- [1, 2, 3] -- [2, 4, 6] -... \ No newline at end of file +model: + file: data/models/compound.model + textures: data/materials/compound +rooms: + - name: "Room #1" + pos: [0, 0, 0] + size: [1000, 1000, 500] + height: 500 + stairtype: none + display: [] + pathfinding: + tilesize: 50 + size: [24, 24] + map: | + ----------------------- + -+++++++++++++++++++++- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+--------------------- + -+--------------------- + -+--------------------- + -+--------------------- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+++++++++++++++++++++- + ----------------------- + - name: Doorway + pos: [1000, 400, 0] + size: [50, 200, 500] + height: 500 + stairtype: none + display: [] + pathfinding: + tilesize: 50 + size: [5, 9] + map: | + ----- + -+++- + ----- + ----- + ----- + ----- + ----- + -+++- + ----- + - name: "Room #2" + pos: [1050, 0, 0] + size: [1000, 1000, 500] + height: 500 + stairtype: none + display: [] + pathfinding: + tilesize: 50 + size: [24, 24] + map: | + ----------------------- + -+++++++++++++++++++++- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + ---------------------+- + ---------------------+- + ---------------------+- + ---------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+-------------------+- + -+++++++++++++++++++++- + ----------------------- +exits: + - room1: "Room #1" + room2: "Room #2" + dir: e + pos: [400, 600] From 99a9aaa591148b3fc038d32e282346ee3c59b635 Mon Sep 17 00:00:00 2001 From: beder Date: Wed, 2 Jul 2008 21:41:54 +0000 Subject: [PATCH 040/295] Specialized the overloaded [] operator for int/unsigned, and added a size() function, so that you can iterate through a sequence node like a vector. --- content.h | 10 ++++++---- main.cpp | 16 ++++++---------- map.cpp | 4 ++-- map.h | 4 ++-- node.cpp | 35 +++++++++++++++++++++++++++++++++++ node.h | 15 ++++++++++++--- sequence.cpp | 16 ++++++++++++++-- sequence.h | 6 ++++-- 8 files changed, 81 insertions(+), 25 deletions(-) diff --git a/content.h b/content.h index 525a10a..298f4db 100644 --- a/content.h +++ b/content.h @@ -21,10 +21,12 @@ namespace YAML virtual void Parse(Scanner *pScanner, const ParserState& state) = 0; virtual void Write(std::ostream& out, int indent) = 0; - virtual bool GetBegin(std::vector ::const_iterator& it) { return false; } - virtual bool GetBegin(std::map ::const_iterator& it) { return false; } - virtual bool GetEnd(std::vector ::const_iterator& it) { return false; } - virtual bool GetEnd(std::map ::const_iterator& it) { return false; } + virtual bool GetBegin(std::vector ::const_iterator& it) const { return false; } + virtual bool GetBegin(std::map ::const_iterator& it) const { return false; } + virtual bool GetEnd(std::vector ::const_iterator& it) const { return false; } + virtual bool GetEnd(std::map ::const_iterator& it) const { return false; } + virtual Node *GetNode(unsigned i) const { return 0; } + virtual unsigned GetSize() const { return 0; } // extraction virtual void Read(std::string& s) { throw InvalidScalar(); } diff --git a/main.cpp b/main.cpp index 3b0fd88..acf1114 100644 --- a/main.cpp +++ b/main.cpp @@ -14,12 +14,9 @@ struct Vec3 { void operator >> (const YAML::Node& node, Vec3& v) { - YAML::Node::Iterator it = node.begin(); - *it >> v.x; - ++it; - *it >> v.y; - ++it; - *it >> v.z; + node[0] >> v.x; + node[1] >> v.y; + node[2] >> v.z; } struct Room { @@ -59,9 +56,9 @@ struct Level { void operator >> (const YAML::Node& node, Level& level) { const YAML::Node& rooms = node["rooms"]; - for(YAML::Node::Iterator it=rooms.begin();it!=rooms.end();++it) { + for(unsigned i=0;i> room; + rooms[i] >> room; level.rooms.push_back(room); } } @@ -78,9 +75,8 @@ int main() YAML::Document doc; parser.GetNextDocument(doc); - const YAML::Node& root = doc.GetRoot(); Level level; - root >> level; + doc.GetRoot() >> level; std::cout << level; } catch(YAML::Exception&) { std::cout << "Error parsing the yaml!\n"; diff --git a/map.cpp b/map.cpp index a6da682..25cb504 100644 --- a/map.cpp +++ b/map.cpp @@ -24,13 +24,13 @@ namespace YAML m_data.clear(); } - bool Map::GetBegin(std::map ::const_iterator& it) + bool Map::GetBegin(std::map ::const_iterator& it) const { it = m_data.begin(); return true; } - bool Map::GetEnd(std::map ::const_iterator& it) + bool Map::GetEnd(std::map ::const_iterator& it) const { it = m_data.end(); return true; diff --git a/map.h b/map.h index bceb705..14ddd30 100644 --- a/map.h +++ b/map.h @@ -14,8 +14,8 @@ namespace YAML virtual ~Map(); void Clear(); - virtual bool GetBegin(std::map ::const_iterator& it); - virtual bool GetEnd(std::map ::const_iterator& it); + virtual bool GetBegin(std::map ::const_iterator& it) const; + virtual bool GetEnd(std::map ::const_iterator& it) const; virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent); diff --git a/node.cpp b/node.cpp index 4f9e7d9..39ff958 100644 --- a/node.cpp +++ b/node.cpp @@ -173,6 +173,41 @@ namespace YAML return Iterator(); } + // size + // . Returns the size of this node, if it's a sequence node. + // . Otherwise, returns zero. + unsigned Node::size() const + { + if(!m_pContent) + return 0; + + return m_pContent->GetSize(); + } + + const Node& Node::operator [] (unsigned u) const + { + if(!m_pContent) + throw BadDereference(); + + Node *pNode = m_pContent->GetNode(u); + if(pNode) + return *pNode; + + return GetValue(u); + } + + const Node& Node::operator [] (int i) const + { + if(!m_pContent) + throw BadDereference(); + + Node *pNode = m_pContent->GetNode(i); + if(pNode) + return *pNode; + + return GetValue(i); + } + /////////////////////////////////////////////////////// // Extraction diff --git a/node.h b/node.h index 8a76c71..47f659b 100644 --- a/node.h +++ b/node.h @@ -50,9 +50,10 @@ namespace YAML Iterator begin() const; Iterator end() const; + unsigned size() const; template - const Node& operator [] (const T& key) const { + const Node& GetValue(const T& key) const { if(!m_pContent) throw BadDereference(); @@ -69,10 +70,18 @@ namespace YAML throw BadDereference(); } - const Node& operator [] (const char *key) const { - return operator [] (std::string(key)); + template + const Node& operator [] (const T& key) const { + return GetValue(key); } + const Node& operator [] (const char *key) const { + return GetValue(std::string(key)); + } + + const Node& operator [] (unsigned u) const; + const Node& operator [] (int i) const; + // extraction friend void operator >> (const Node& node, std::string& s); friend void operator >> (const Node& node, int& i); diff --git a/sequence.cpp b/sequence.cpp index 40dc3e0..fce8639 100644 --- a/sequence.cpp +++ b/sequence.cpp @@ -22,18 +22,30 @@ namespace YAML m_data.clear(); } - bool Sequence::GetBegin(std::vector ::const_iterator& it) + bool Sequence::GetBegin(std::vector ::const_iterator& it) const { it = m_data.begin(); return true; } - bool Sequence::GetEnd(std::vector ::const_iterator& it) + bool Sequence::GetEnd(std::vector ::const_iterator& it) const { it = m_data.end(); return true; } + Node *Sequence::GetNode(unsigned i) const + { + if(i < m_data.size()) + return m_data[i]; + return 0; + } + + unsigned Sequence::GetSize() const + { + return m_data.size(); + } + void Sequence::Parse(Scanner *pScanner, const ParserState& state) { Clear(); diff --git a/sequence.h b/sequence.h index 3897112..5be190e 100644 --- a/sequence.h +++ b/sequence.h @@ -14,8 +14,10 @@ namespace YAML virtual ~Sequence(); void Clear(); - virtual bool GetBegin(std::vector ::const_iterator& it); - virtual bool GetEnd(std::vector ::const_iterator& it); + virtual bool GetBegin(std::vector ::const_iterator& it) const; + virtual bool GetEnd(std::vector ::const_iterator& it) const; + virtual Node *GetNode(unsigned i) const; + virtual unsigned GetSize() const; virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent); From c4c873733bbd0a2566ec8a9a320d280fd47280e8 Mon Sep 17 00:00:00 2001 From: beder Date: Fri, 4 Jul 2008 22:56:43 +0000 Subject: [PATCH 041/295] Removed the document class (since it's really just a root node, and that's it). --- document.cpp | 63 ---------------------------------------------- document.h | 26 ------------------- main.cpp | 4 +-- node.h | 1 + parser.cpp | 24 ++++++++++++++++-- parser.h | 4 +-- yaml-reader.vcproj | 8 ------ 7 files changed, 27 insertions(+), 103 deletions(-) delete mode 100644 document.cpp delete mode 100644 document.h diff --git a/document.cpp b/document.cpp deleted file mode 100644 index 8d4d55f..0000000 --- a/document.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include "document.h" -#include "node.h" -#include "token.h" -#include "scanner.h" - -namespace YAML -{ - Document::Document(): m_pRoot(0) - { - } - - Document::~Document() - { - Clear(); - } - - void Document::Clear() - { - delete m_pRoot; - m_pRoot = 0; - } - - void Document::Parse(Scanner *pScanner, const ParserState& state) - { - Clear(); - - // we better have some tokens in the queue - if(!pScanner->PeekNextToken()) - return; - - // first eat doc start (optional) - if(pScanner->PeekNextToken()->type == TT_DOC_START) - pScanner->EatNextToken(); - - // now create our root node and parse it - m_pRoot = new Node; - m_pRoot->Parse(pScanner, state); - - // and finally eat any doc ends we see - while(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_DOC_END) - pScanner->EatNextToken(); - } - - const Node& Document::GetRoot() const - { - if(!m_pRoot) - throw; - - return *m_pRoot; - } - - std::ostream& operator << (std::ostream& out, const Document& doc) - { - out << "---\n"; - if(!doc.m_pRoot) { - out << "{empty node}\n"; - return out; - } - - doc.m_pRoot->Write(out, 0); - return out; - } -} diff --git a/document.h b/document.h deleted file mode 100644 index 3517cf0..0000000 --- a/document.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include -#include "parserstate.h" - -namespace YAML -{ - class Node; - class Scanner; - - class Document - { - public: - Document(); - ~Document(); - - void Clear(); - void Parse(Scanner *pScanner, const ParserState& state); - const Node& GetRoot() const; - - friend std::ostream& operator << (std::ostream& out, const Document& doc); - - private: - Node *m_pRoot; - }; -} diff --git a/main.cpp b/main.cpp index acf1114..d1b5d28 100644 --- a/main.cpp +++ b/main.cpp @@ -72,11 +72,11 @@ int main() if(!parser) return 0; - YAML::Document doc; + YAML::Node doc; parser.GetNextDocument(doc); Level level; - doc.GetRoot() >> level; + doc >> level; std::cout << level; } catch(YAML::Exception&) { std::cout << "Error parsing the yaml!\n"; diff --git a/node.h b/node.h index 47f659b..a86ba15 100644 --- a/node.h +++ b/node.h @@ -48,6 +48,7 @@ namespace YAML void Parse(Scanner *pScanner, const ParserState& state); void Write(std::ostream& out, int indent); + // accessors Iterator begin() const; Iterator end() const; unsigned size() const; diff --git a/parser.cpp b/parser.cpp index 7b42d43..decb663 100644 --- a/parser.cpp +++ b/parser.cpp @@ -22,15 +22,35 @@ namespace YAML return m_pScanner->PeekNextToken() != 0; } - void Parser::GetNextDocument(Document& document) + // GetNextDocument + // . Reads the next document in the queue (of tokens). + // . Throws (ScannerException|ParserException)s on errors. + void Parser::GetNextDocument(Node& document) { + // clear node + document.Clear(); + // first read directives ParseDirectives(); - // then parse the document + // we better have some tokens in the queue + if(!m_pScanner->PeekNextToken()) + return; + + // first eat doc start (optional) + if(m_pScanner->PeekNextToken()->type == TT_DOC_START) + m_pScanner->EatNextToken(); + + // now parse our root node document.Parse(m_pScanner, m_state); + + // and finally eat any doc ends we see + while(m_pScanner->PeekNextToken() && m_pScanner->PeekNextToken()->type == TT_DOC_END) + m_pScanner->EatNextToken(); } + // ParseDirectives + // . Reads any directives that are next in the queue. void Parser::ParseDirectives() { bool readDirective = false; diff --git a/parser.h b/parser.h index cd42017..a26446f 100644 --- a/parser.h +++ b/parser.h @@ -4,7 +4,7 @@ #include #include #include -#include "document.h" +#include "node.h" #include "parserstate.h" namespace YAML @@ -20,7 +20,7 @@ namespace YAML operator bool() const; - void GetNextDocument(Document& document); + void GetNextDocument(Node& document); void PrintTokens(std::ostream& out); private: diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index 4e74139..455b71d 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -216,10 +216,6 @@ RelativePath=".\content.cpp" > - - @@ -298,10 +294,6 @@ RelativePath=".\content.h" > - - From 5feaef3748c8fc574034ba85553dfab4665134e7 Mon Sep 17 00:00:00 2001 From: beder Date: Fri, 4 Jul 2008 22:57:52 +0000 Subject: [PATCH 042/295] --- main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/main.cpp b/main.cpp index d1b5d28..29c885f 100644 --- a/main.cpp +++ b/main.cpp @@ -1,5 +1,4 @@ #include "parser.h" -#include "node.h" #include #include From ba97c9f719fc22967fc09a81c2e10c9823cf42f2 Mon Sep 17 00:00:00 2001 From: beder Date: Sat, 5 Jul 2008 05:28:23 +0000 Subject: [PATCH 043/295] Rewrote the output so that it emits correct YAML. Fixed a bug in the last newline of a block folded scalar. --- content.h | 2 +- main.cpp | 5 +-- map.cpp | 27 +++++++----- map.h | 2 +- node.cpp | 36 ++++++++++------ node.h | 5 ++- scalar.cpp | 19 ++++++--- scalar.h | 2 +- scanscalar.cpp | 7 ++- sequence.cpp | 22 +++++++--- sequence.h | 2 +- test.yaml | 114 ++++++++----------------------------------------- 12 files changed, 98 insertions(+), 145 deletions(-) diff --git a/content.h b/content.h index 298f4db..9f9ac25 100644 --- a/content.h +++ b/content.h @@ -19,7 +19,7 @@ namespace YAML virtual ~Content(); virtual void Parse(Scanner *pScanner, const ParserState& state) = 0; - virtual void Write(std::ostream& out, int indent) = 0; + virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) = 0; virtual bool GetBegin(std::vector ::const_iterator& it) const { return false; } virtual bool GetBegin(std::map ::const_iterator& it) const { return false; } diff --git a/main.cpp b/main.cpp index 29c885f..ef99a1d 100644 --- a/main.cpp +++ b/main.cpp @@ -73,10 +73,7 @@ int main() YAML::Node doc; parser.GetNextDocument(doc); - - Level level; - doc >> level; - std::cout << level; + std::cout << doc; } catch(YAML::Exception&) { std::cout << "Error parsing the yaml!\n"; } diff --git a/map.cpp b/map.cpp index 25cb504..b448265 100644 --- a/map.cpp +++ b/map.cpp @@ -125,22 +125,27 @@ namespace YAML } } - void Map::Write(std::ostream& out, int indent) + void Map::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) { - for(int i=0;ifirst->Write(out, indent + 2); + if((startedLine && !onlyOneCharOnLine) || it != m_data.begin()) { + for(int i=0;ifirst->Write(out, indent + 1, true, it!= m_data.begin() || !startedLine || onlyOneCharOnLine); + + for(int i=0;isecond->Write(out, indent + 2); + out << ": "; + it->second->Write(out, indent + 1, true, true); } + + if(m_data.empty()) + out << std::endl; } } diff --git a/map.h b/map.h index 14ddd30..d3a327c 100644 --- a/map.h +++ b/map.h @@ -17,7 +17,7 @@ namespace YAML virtual bool GetBegin(std::map ::const_iterator& it) const; virtual bool GetEnd(std::map ::const_iterator& it) const; virtual void Parse(Scanner *pScanner, const ParserState& state); - virtual void Write(std::ostream& out, int indent); + virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); private: void ParseBlock(Scanner *pScanner, const ParserState& state); diff --git a/node.cpp b/node.cpp index 39ff958..c998a45 100644 --- a/node.cpp +++ b/node.cpp @@ -112,28 +112,30 @@ namespace YAML pScanner->PopNextToken(); } - void Node::Write(std::ostream& out, int indent) + void Node::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const { - if(m_tag != "") { - for(int i=0;i "; + startedLine = true; + onlyOneCharOnLine = false; } if(!m_pContent) { - for(int i=0;iWrite(out, indent); + m_pContent->Write(out, indent, startedLine, onlyOneCharOnLine); } } @@ -266,4 +268,10 @@ namespace YAML node.m_pContent->Read(c); } + + std::ostream& operator << (std::ostream& out, const Node& node) + { + node.Write(out, 0, false, false); + return out; + } } diff --git a/node.h b/node.h index a86ba15..988ee1c 100644 --- a/node.h +++ b/node.h @@ -46,7 +46,7 @@ namespace YAML void Clear(); void Parse(Scanner *pScanner, const ParserState& state); - void Write(std::ostream& out, int indent); + void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const; // accessors Iterator begin() const; @@ -92,6 +92,9 @@ namespace YAML friend void operator >> (const Node& node, double& d); friend void operator >> (const Node& node, char& c); + // insertion + friend std::ostream& operator << (std::ostream& out, const Node& node); + private: void ParseHeader(Scanner *pScanner, const ParserState& state); void ParseTag(Scanner *pScanner, const ParserState& state); diff --git a/scalar.cpp b/scalar.cpp index c33ae32..20b2671 100644 --- a/scalar.cpp +++ b/scalar.cpp @@ -21,14 +21,19 @@ namespace YAML delete pToken; } - void Scalar::Write(std::ostream& out, int indent) + void Scalar::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) { - for(int i=0;iWrite(out, indent + 1); + if(startedLine && !onlyOneCharOnLine) + out << std::endl; + + for(unsigned i=0;i 0) { + for(int j=0;jWrite(out, indent + 1, true, i > 0 || !startedLine || onlyOneCharOnLine); + } + + if(m_data.empty()) + out << std::endl; } } diff --git a/sequence.h b/sequence.h index 5be190e..d305073 100644 --- a/sequence.h +++ b/sequence.h @@ -20,7 +20,7 @@ namespace YAML virtual unsigned GetSize() const; virtual void Parse(Scanner *pScanner, const ParserState& state); - virtual void Write(std::ostream& out, int indent); + virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); private: void ParseBlock(Scanner *pScanner, const ParserState& state); diff --git a/test.yaml b/test.yaml index 8a9714c..f7be014 100644 --- a/test.yaml +++ b/test.yaml @@ -1,97 +1,17 @@ ---- -model: - file: data/models/compound.model - textures: data/materials/compound -rooms: - - name: "Room #1" - pos: [0, 0, 0] - size: [1000, 1000, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [24, 24] - map: | - ----------------------- - -+++++++++++++++++++++- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+--------------------- - -+--------------------- - -+--------------------- - -+--------------------- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+++++++++++++++++++++- - ----------------------- - - name: Doorway - pos: [1000, 400, 0] - size: [50, 200, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [5, 9] - map: | - ----- - -+++- - ----- - ----- - ----- - ----- - ----- - -+++- - ----- - - name: "Room #2" - pos: [1050, 0, 0] - size: [1000, 1000, 500] - height: 500 - stairtype: none - display: [] - pathfinding: - tilesize: 50 - size: [24, 24] - map: | - ----------------------- - -+++++++++++++++++++++- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - ---------------------+- - ---------------------+- - ---------------------+- - ---------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+-------------------+- - -+++++++++++++++++++++- - ----------------------- -exits: - - room1: "Room #1" - room2: "Room #2" - dir: e - pos: [400, 600] +literal: | + Here's a literal scalar. + That's a newline. + + Let's go... +folded: > + Here's a folded scalar that + wraps over to a newline. + + Let's go... +regular: Here's a regular + scalar that keeps + on wrapping... + + + Let's go! +and last key: so it doesn't go bonkers \ No newline at end of file From 3cad5a2ed01c54a1bed857ec9e955c57c54597ff Mon Sep 17 00:00:00 2001 From: beder Date: Sat, 5 Jul 2008 19:00:58 +0000 Subject: [PATCH 044/295] Wrote some tests, but they don't work because it doesn't output maps in a canonical form. --- main.cpp | 27 +++++++++------- parser.cpp | 10 ++++-- parser.h | 1 + tests.cpp | 80 ++++++++++++++++++++++++++++++++++++++++++++++ tests.h | 10 ++++++ tests/mixed.yaml | 32 +++++++++++++++++++ tests/simple.yaml | 13 ++++++++ yaml-reader.vcproj | 8 +++++ 8 files changed, 167 insertions(+), 14 deletions(-) create mode 100644 tests.cpp create mode 100644 tests.h create mode 100644 tests/mixed.yaml create mode 100644 tests/simple.yaml diff --git a/main.cpp b/main.cpp index ef99a1d..6588557 100644 --- a/main.cpp +++ b/main.cpp @@ -1,4 +1,5 @@ #include "parser.h" +#include "tests.h" #include #include @@ -64,21 +65,23 @@ void operator >> (const YAML::Node& node, Level& level) int main() { - std::ifstream fin("test.yaml"); + YAML::Test::RunAll(); - try { - YAML::Parser parser(fin); - if(!parser) - return 0; + //std::ifstream fin("test.yaml"); - YAML::Node doc; - parser.GetNextDocument(doc); - std::cout << doc; - } catch(YAML::Exception&) { - std::cout << "Error parsing the yaml!\n"; - } + //try { + // YAML::Parser parser(fin); + // if(!parser) + // return 0; + + // YAML::Node doc; + // parser.GetNextDocument(doc); + // std::cout << doc; + //} catch(YAML::Exception&) { + // std::cout << "Error parsing the yaml!\n"; + //} getchar(); return 0; -} \ No newline at end of file +} diff --git a/parser.cpp b/parser.cpp index decb663..46c92b8 100644 --- a/parser.cpp +++ b/parser.cpp @@ -8,8 +8,7 @@ namespace YAML { Parser::Parser(std::istream& in): m_pScanner(0) { - m_pScanner = new Scanner(in); - m_state.Reset(); + Load(in); } Parser::~Parser() @@ -22,6 +21,13 @@ namespace YAML return m_pScanner->PeekNextToken() != 0; } + void Parser::Load(std::istream& in) + { + delete m_pScanner; + m_pScanner = new Scanner(in); + m_state.Reset(); + } + // GetNextDocument // . Reads the next document in the queue (of tokens). // . Throws (ScannerException|ParserException)s on errors. diff --git a/parser.h b/parser.h index a26446f..33c24c1 100644 --- a/parser.h +++ b/parser.h @@ -20,6 +20,7 @@ namespace YAML operator bool() const; + void Load(std::istream& in); void GetNextDocument(Node& document); void PrintTokens(std::ostream& out); diff --git a/tests.cpp b/tests.cpp new file mode 100644 index 0000000..2d9b476 --- /dev/null +++ b/tests.cpp @@ -0,0 +1,80 @@ +#include "tests.h" +#include "parser.h" +#include +#include +#include +#include + +namespace YAML +{ + namespace Test + { + // runs all the tests on all data we have + void RunAll() + { + std::vector files; + files.push_back("tests/simple.yaml"); + files.push_back("tests/mixed.yaml"); + + bool passed = true; + for(unsigned i=0;i + +namespace YAML +{ + namespace Test { + void RunAll(); + + bool Inout(const std::string& file); + } +} \ No newline at end of file diff --git a/tests/mixed.yaml b/tests/mixed.yaml new file mode 100644 index 0000000..88da1e7 --- /dev/null +++ b/tests/mixed.yaml @@ -0,0 +1,32 @@ +- the main thing is a sequence +- here's a key: value + and another: value +- let's inline: [1, 2, 3] + and an inline map: {key: value, 243: 101} +- and multiple indents: + - here's + - a + - list + and another: + - list + - of + - things +- maybe now: + let's: get + pretty: + deep: here + in: + the: nesting + just: to + confuse: + the: heck + out: + - of + - the: parser + if: + - we + - can + - do: that + what: do + you: think? + \ No newline at end of file diff --git a/tests/simple.yaml b/tests/simple.yaml new file mode 100644 index 0000000..55b2d21 --- /dev/null +++ b/tests/simple.yaml @@ -0,0 +1,13 @@ +--- +just a scalar +--- +and another scalar +--- +now an end document +... +--- +and now two +... +... +--- +and that's it \ No newline at end of file diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index 455b71d..0d77cd1 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -165,6 +165,10 @@ RelativePath=".\main.cpp" > + + @@ -247,6 +251,10 @@ RelativePath=".\exceptions.h" > + + From 1acc0e49824391ba3ae0ff9073503fda0b2c3161 Mon Sep 17 00:00:00 2001 From: beder Date: Sun, 6 Jul 2008 00:06:36 +0000 Subject: [PATCH 045/295] Added a (recursive) ordering, so we have a canonical output that we can compare. --- content.h | 14 ++++++- iterator.cpp | 2 +- ltnode.h | 10 +++++ map.cpp | 91 ++++++++++++++++++++++++++++++++++------------ map.h | 12 ++++-- node.cpp | 30 ++++++++++++++- node.h | 9 ++++- scalar.cpp | 15 ++++++++ scalar.h | 6 +++ sequence.cpp | 22 +++++++++++ sequence.h | 6 +++ test.yaml | 20 ++-------- tests.cpp | 3 +- tests/scalars.yaml | 24 ++++++++++++ yaml-reader.vcproj | 4 ++ 15 files changed, 217 insertions(+), 51 deletions(-) create mode 100644 ltnode.h create mode 100644 tests/scalars.yaml diff --git a/content.h b/content.h index 9f9ac25..3189478 100644 --- a/content.h +++ b/content.h @@ -5,12 +5,16 @@ #include #include "parserstate.h" #include "exceptions.h" +#include "ltnode.h" namespace YAML { class Scanner; class Parser; class Node; + class Scalar; + class Sequence; + class Map; class Content { @@ -22,9 +26,9 @@ namespace YAML virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) = 0; virtual bool GetBegin(std::vector ::const_iterator& it) const { return false; } - virtual bool GetBegin(std::map ::const_iterator& it) const { return false; } + virtual bool GetBegin(std::map ::const_iterator& it) const { return false; } virtual bool GetEnd(std::vector ::const_iterator& it) const { return false; } - virtual bool GetEnd(std::map ::const_iterator& it) const { return false; } + virtual bool GetEnd(std::map ::const_iterator& it) const { return false; } virtual Node *GetNode(unsigned i) const { return 0; } virtual unsigned GetSize() const { return 0; } @@ -37,6 +41,12 @@ namespace YAML virtual void Read(double& d) { throw InvalidScalar(); } virtual void Read(char& c) { throw InvalidScalar(); } + // ordering + virtual int Compare(Content *pContent) { return 0; } + virtual int Compare(Scalar *pScalar) { return 0; } + virtual int Compare(Sequence *pSeq) { return 0; } + virtual int Compare(Map *pMap) { return 0; } + protected: }; } diff --git a/iterator.cpp b/iterator.cpp index 67d050d..bd671be 100644 --- a/iterator.cpp +++ b/iterator.cpp @@ -11,7 +11,7 @@ namespace YAML { } - Node::Iterator::Iterator(std::map ::const_iterator it): mapIter(it), type(IT_MAP) + Node::Iterator::Iterator(std::map ::const_iterator it): mapIter(it), type(IT_MAP) { } diff --git a/ltnode.h b/ltnode.h new file mode 100644 index 0000000..af8c1bb --- /dev/null +++ b/ltnode.h @@ -0,0 +1,10 @@ +#pragma once + +namespace YAML +{ + class Node; + + struct ltnode { + bool operator()(const Node *pNode1, const Node *pNode2) const; + }; +} diff --git a/map.cpp b/map.cpp index b448265..e23c2af 100644 --- a/map.cpp +++ b/map.cpp @@ -24,13 +24,13 @@ namespace YAML m_data.clear(); } - bool Map::GetBegin(std::map ::const_iterator& it) const + bool Map::GetBegin(std::map ::const_iterator& it) const { it = m_data.begin(); return true; } - bool Map::GetEnd(std::map ::const_iterator& it) const + bool Map::GetEnd(std::map ::const_iterator& it) const { it = m_data.end(); return true; @@ -68,15 +68,22 @@ namespace YAML Node *pKey = new Node; Node *pValue = new Node; - m_data[pKey] = pValue; - // grab key - pKey->Parse(pScanner, state); + try { + // grab key + pKey->Parse(pScanner, state); - // now grab value (optional) - if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { - pScanner->PopNextToken(); - pValue->Parse(pScanner, state); + // now grab value (optional) + if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { + pScanner->PopNextToken(); + pValue->Parse(pScanner, state); + } + + m_data[pKey] = pValue; + } catch(Exception& e) { + delete pKey; + delete pValue; + throw e; } } } @@ -105,23 +112,31 @@ namespace YAML Node *pKey = new Node; Node *pValue = new Node; - m_data[pKey] = pValue; - // grab key - pKey->Parse(pScanner, state); + try { + // grab key + pKey->Parse(pScanner, state); - // now grab value (optional) - if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { - pScanner->PopNextToken(); - pValue->Parse(pScanner, state); + // now grab value (optional) + if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { + pScanner->PopNextToken(); + 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) + pToken = pScanner->PeekNextToken(); + if(pToken->type == TT_FLOW_ENTRY) + pScanner->EatNextToken(); + else if(pToken->type != TT_FLOW_MAP_END) + throw MapEndNotFound(); + + m_data[pKey] = pValue; + } catch(Exception& e) { + // clean up and rethrow + delete pKey; + delete pValue; + throw e; } - - // now eat the separator (or could be a map end, which we ignore - but if it's neither, then it's a bad node) - pToken = pScanner->PeekNextToken(); - if(pToken->type == TT_FLOW_ENTRY) - pScanner->EatNextToken(); - else if(pToken->type != TT_FLOW_MAP_END) - throw MapEndNotFound(); } } @@ -148,4 +163,34 @@ namespace YAML if(m_data.empty()) out << std::endl; } + + int Map::Compare(Content *pContent) + { + return -pContent->Compare(this); + } + + int Map::Compare(Map *pMap) + { + node_map::const_iterator it = m_data.begin(), jt = pMap->m_data.begin(); + while(1) { + if(it == m_data.end()) { + if(jt == pMap->m_data.end()) + return 0; + else + return -1; + } + if(jt == pMap->m_data.end()) + return 1; + + int cmp = it->first->Compare(*jt->first); + if(cmp != 0) + return cmp; + + cmp = it->second->Compare(*jt->second); + if(cmp != 0) + return cmp; + } + + return 0; + } } diff --git a/map.h b/map.h index d3a327c..3ebd3f4 100644 --- a/map.h +++ b/map.h @@ -14,17 +14,23 @@ namespace YAML virtual ~Map(); void Clear(); - virtual bool GetBegin(std::map ::const_iterator& it) const; - virtual bool GetEnd(std::map ::const_iterator& it) const; + virtual bool GetBegin(std::map ::const_iterator& it) const; + virtual bool GetEnd(std::map ::const_iterator& it) const; virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); + // ordering + virtual int Compare(Content *pContent); + virtual int Compare(Scalar *pScalar) { return 1; } + virtual int Compare(Sequence *pSeq) { return 1; } + virtual int Compare(Map *pMap); + private: void ParseBlock(Scanner *pScanner, const ParserState& state); void ParseFlow(Scanner *pScanner, const ParserState& state); protected: - typedef std::map node_map; + typedef std::map node_map; node_map m_data; }; } diff --git a/node.cpp b/node.cpp index c998a45..c31fe96 100644 --- a/node.cpp +++ b/node.cpp @@ -9,6 +9,12 @@ namespace YAML { + // the ordering! + bool ltnode::operator ()(const Node *pNode1, const Node *pNode2) const + { + return *pNode1 < *pNode2; + } + Node::Node(): m_pContent(0), m_alias(false) { } @@ -150,7 +156,7 @@ namespace YAML if(m_pContent->GetBegin(seqIter)) return Iterator(seqIter); - std::map ::const_iterator mapIter; + std::map ::const_iterator mapIter; if(m_pContent->GetBegin(mapIter)) return Iterator(mapIter); @@ -168,7 +174,7 @@ namespace YAML if(m_pContent->GetEnd(seqIter)) return Iterator(seqIter); - std::map ::const_iterator mapIter; + std::map ::const_iterator mapIter; if(m_pContent->GetEnd(mapIter)) return Iterator(mapIter); @@ -274,4 +280,24 @@ namespace YAML node.Write(out, 0, false, false); return out; } + + int Node::Compare(const Node& rhs) const + { + // Step 1: no content is the smallest + if(!m_pContent) { + if(rhs.m_pContent) + return -1; + else + return 0; + } + if(!rhs.m_pContent) + return 1; + + return m_pContent->Compare(rhs.m_pContent); + } + + bool operator < (const Node& n1, const Node& n2) + { + return n1.Compare(n2) < 0; + } } diff --git a/node.h b/node.h index 988ee1c..9bc88ca 100644 --- a/node.h +++ b/node.h @@ -6,6 +6,7 @@ #include #include "parserstate.h" #include "exceptions.h" +#include "ltnode.h" namespace YAML { @@ -20,7 +21,7 @@ namespace YAML public: Iterator(); Iterator(std::vector ::const_iterator it); - Iterator(std::map ::const_iterator it); + Iterator(std::map ::const_iterator it); ~Iterator(); friend bool operator == (const Iterator& it, const Iterator& jt); @@ -37,7 +38,7 @@ namespace YAML ITER_TYPE type; std::vector ::const_iterator seqIter; - std::map ::const_iterator mapIter; + std::map ::const_iterator mapIter; }; public: @@ -95,6 +96,10 @@ namespace YAML // insertion friend std::ostream& operator << (std::ostream& out, const Node& node); + // ordering + int Compare(const Node& rhs) const; + friend bool operator < (const Node& n1, const Node& n2); + private: void ParseHeader(Scanner *pScanner, const ParserState& state); void ParseTag(Scanner *pScanner, const ParserState& state); diff --git a/scalar.cpp b/scalar.cpp index 20b2671..6be1bf4 100644 --- a/scalar.cpp +++ b/scalar.cpp @@ -88,4 +88,19 @@ namespace YAML if(!data) throw InvalidScalar(); } + + int Scalar::Compare(Content *pContent) + { + return -pContent->Compare(this); + } + + int Scalar::Compare(Scalar *pScalar) + { + if(m_data < pScalar->m_data) + return -1; + else if(m_data > pScalar->m_data) + return 1; + else + return 0; + } } diff --git a/scalar.h b/scalar.h index 95b9062..0da9df6 100644 --- a/scalar.h +++ b/scalar.h @@ -23,6 +23,12 @@ namespace YAML virtual void Read(double& d); virtual void Read(char& c); + // ordering + virtual int Compare(Content *pContent); + virtual int Compare(Scalar *pScalar); + virtual int Compare(Sequence *pSeq) { return -1; } + virtual int Compare(Map *pMap) { return -1; } + protected: std::string m_data; }; diff --git a/sequence.cpp b/sequence.cpp index 5e08835..1ec82de 100644 --- a/sequence.cpp +++ b/sequence.cpp @@ -151,4 +151,26 @@ namespace YAML if(m_data.empty()) out << std::endl; } + + int Sequence::Compare(Content *pContent) + { + return -pContent->Compare(this); + } + + int Sequence::Compare(Sequence *pSeq) + { + unsigned n = m_data.size(), m = pSeq->m_data.size(); + if(n < m) + return -1; + else if(n > m) + return 1; + + for(unsigned i=0;iCompare(*pSeq->m_data[i]); + if(cmp != 0) + return cmp; + } + + return 0; + } } diff --git a/sequence.h b/sequence.h index d305073..35b7765 100644 --- a/sequence.h +++ b/sequence.h @@ -22,6 +22,12 @@ namespace YAML virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); + // ordering + virtual int Compare(Content *pContent); + virtual int Compare(Scalar *pScalar) { return 1; } + virtual int Compare(Sequence *pSeq); + virtual int Compare(Map *pMap) { return -1; } + private: void ParseBlock(Scanner *pScanner, const ParserState& state); void ParseImplicit(Scanner *pScanner, const ParserState& state); diff --git a/test.yaml b/test.yaml index f7be014..28e1b7d 100644 --- a/test.yaml +++ b/test.yaml @@ -1,17 +1,3 @@ -literal: | - Here's a literal scalar. - That's a newline. - - Let's go... -folded: > - Here's a folded scalar that - wraps over to a newline. - - Let's go... -regular: Here's a regular - scalar that keeps - on wrapping... - - - Let's go! -and last key: so it doesn't go bonkers \ No newline at end of file +abeginning: value +zend: value +middle: value \ No newline at end of file diff --git a/tests.cpp b/tests.cpp index 2d9b476..01df50b 100644 --- a/tests.cpp +++ b/tests.cpp @@ -15,6 +15,7 @@ namespace YAML std::vector files; files.push_back("tests/simple.yaml"); files.push_back("tests/mixed.yaml"); + files.push_back("tests/scalars.yaml"); bool passed = true; for(unsigned i=0;i + and a folded scalar... so we + can just keep writing various + things. And if we want to keep indentation: + + we just indent a little + see, this stays indented +- >- + Here's a folded scalar + that gets chomped. +- |- + And here's a literal scalar + that gets chomped. +- >2 + Here's a folded scalar + that starts with some indentation. \ No newline at end of file diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index 0d77cd1..5239b09 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -302,6 +302,10 @@ RelativePath=".\content.h" > + + From 2f5c19fa004f868bf20586a6ae3574fdc050ebbd Mon Sep 17 00:00:00 2001 From: beder Date: Tue, 8 Jul 2008 05:48:38 +0000 Subject: [PATCH 046/295] Combined the myriad ScannerExceptions and ParserExceptions to a single ParserException class that has a message and a line/column position in the file where the error occurred. --- exceptions.h | 48 ++++++------------------------- exp.cpp | 18 ++++++++---- map.cpp | 10 +++---- parser.cpp | 33 ++++++++++----------- parser.h | 8 +++--- scanner.cpp | 8 +++--- scanscalar.cpp | 6 ++-- scantoken.cpp | 78 +++++++++++++++++++++++++++++++++----------------- sequence.cpp | 8 +++--- simplekey.cpp | 4 +-- tests.cpp | 3 +- token.h | 3 +- 12 files changed, 114 insertions(+), 113 deletions(-) diff --git a/exceptions.h b/exceptions.h index 585963b..017b0b1 100644 --- a/exceptions.h +++ b/exceptions.h @@ -5,48 +5,16 @@ namespace YAML { class Exception: public std::exception {}; - class ScannerException: public Exception {}; - class ParserException: public Exception {}; + class ParserException: public Exception { + public: + ParserException(int line_, int column_, const std::string& msg_) + : line(line_), column(column_), msg(msg_) {} + int line, column; + std::string msg; + }; + class RepresentationException: public Exception {}; - // scanner exceptions - class UnknownToken: public ScannerException {}; - class IllegalBlockEntry: public ScannerException {}; - class IllegalMapKey: public ScannerException {}; - class IllegalMapValue: public ScannerException {}; - class IllegalScalar: public ScannerException {}; - class IllegalTabInIndentation: public ScannerException {}; - class IllegalFlowEnd: public ScannerException {}; - class IllegalDocIndicator: public ScannerException {}; - class IllegalEOF: public ScannerException {}; - class RequiredSimpleKeyNotFound: public ScannerException {}; - class ZeroIndentationInBlockScalar: public ScannerException {}; - class UnexpectedCharacterInBlockScalar: public ScannerException {}; - class AnchorNotFound: public ScannerException {}; - class IllegalCharacterInAnchor: public ScannerException {}; - - class UnknownEscapeSequence: public ScannerException { - public: - UnknownEscapeSequence(char ch_): ch(ch_) {} - char ch; - }; - class NonHexNumber: public ScannerException { - public: - NonHexNumber(char ch_): ch(ch_) {} - char ch; - }; - class InvalidUnicode: public ScannerException { - public: - InvalidUnicode(unsigned value_): value(value_) {} - unsigned value; - }; - - // parser exceptions - class MapEndNotFound: public ParserException {}; - class SeqEndNotFound: public ParserException {}; - class BadYAMLDirective: public ParserException {}; - class BadTAGDirective: public ParserException {}; - // representation exceptions class InvalidScalar: public RepresentationException {}; class BadDereference: public RepresentationException {}; diff --git a/exp.cpp b/exp.cpp index 493654c..f766de6 100644 --- a/exp.cpp +++ b/exp.cpp @@ -1,11 +1,12 @@ #include "exp.h" #include "exceptions.h" +#include namespace YAML { namespace Exp { - unsigned ParseHex(std::string str) + unsigned ParseHex(const std::string& str, int line, int column) { unsigned value = 0; for(unsigned i=0;i= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) - throw InvalidUnicode(value); + if((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) { + std::stringstream msg; + msg << "invalid unicode: " << value; + throw ParserException(in.line, in.column, msg.str()); + } // now break it up into chars if(value <= 0x7F) @@ -101,7 +105,9 @@ namespace YAML case 'U': return Escape(in, 8); } - throw UnknownEscapeSequence(ch); + std::stringstream msg; + msg << "unknown escape character: " << ch; + throw ParserException(in.line, in.column, msg.str()); } } } diff --git a/map.cpp b/map.cpp index e23c2af..0687f34 100644 --- a/map.cpp +++ b/map.cpp @@ -57,10 +57,10 @@ namespace YAML while(1) { Token *pToken = pScanner->PeekNextToken(); if(!pToken) - throw MapEndNotFound(); + throw ParserException(-1, -1, "end of map not found"); if(pToken->type != TT_KEY && pToken->type != TT_BLOCK_END) - throw MapEndNotFound(); + throw ParserException(pToken->line, pToken->column, "end of map not found"); pScanner->PopNextToken(); if(pToken->type == TT_BLOCK_END) @@ -96,7 +96,7 @@ namespace YAML while(1) { Token *pToken = pScanner->PeekNextToken(); if(!pToken) - throw MapEndNotFound(); + throw ParserException(-1, -1, "end of map flow not found"); // first check for end if(pToken->type == TT_FLOW_MAP_END) { @@ -106,7 +106,7 @@ namespace YAML // now it better be a key if(pToken->type != TT_KEY) - throw MapEndNotFound(); + throw ParserException(pToken->line, pToken->column, "end of map flow not found"); pScanner->PopNextToken(); @@ -128,7 +128,7 @@ namespace YAML if(pToken->type == TT_FLOW_ENTRY) pScanner->EatNextToken(); else if(pToken->type != TT_FLOW_MAP_END) - throw MapEndNotFound(); + throw ParserException(pToken->line, pToken->column, "end of map flow not found"); m_data[pKey] = pValue; } catch(Exception& e) { diff --git a/parser.cpp b/parser.cpp index 46c92b8..82935d1 100644 --- a/parser.cpp +++ b/parser.cpp @@ -30,7 +30,7 @@ namespace YAML // GetNextDocument // . Reads the next document in the queue (of tokens). - // . Throws (ScannerException|ParserException)s on errors. + // . Throws (ParserException|ParserException)s on errors. void Parser::GetNextDocument(Node& document) { // clear node @@ -72,42 +72,43 @@ namespace YAML m_state.Reset(); readDirective = true; - HandleDirective(pToken->value, pToken->params); + HandleDirective(pToken); m_pScanner->PopNextToken(); } } - void Parser::HandleDirective(const std::string& name, const std::vector & params) + void Parser::HandleDirective(Token *pToken) { - if(name == "YAML") - HandleYamlDirective(params); - else if(name == "TAG") - HandleTagDirective(params); + if(pToken->value == "YAML") + HandleYamlDirective(pToken); + else if(pToken->value == "TAG") + HandleTagDirective(pToken); } // HandleYamlDirective // . Should be of the form 'major.minor' (like a version number) - void Parser::HandleYamlDirective(const std::vector & params) + void Parser::HandleYamlDirective(Token *pToken) { - if(params.size() != 1) - throw BadYAMLDirective(); + if(pToken->params.size() != 1) + throw ParserException(pToken->line, pToken->column, "YAML directives must have exactly one argument"); - std::stringstream str(params[0]); + std::stringstream str(pToken->params[0]); str >> m_state.version.major; str.get(); str >> m_state.version.minor; if(!str) - throw BadYAMLDirective(); // TODO: or throw if there are any more characters in the stream? + throw ParserException(pToken->line, pToken->column, "bad YAML directive"); + // TODO: or throw if there are any more characters in the stream? // TODO: throw on major > 1? warning on major == 1, minor > 2? } - void Parser::HandleTagDirective(const std::vector & params) + void Parser::HandleTagDirective(Token *pToken) { - if(params.size() != 2) - throw BadTAGDirective(); + if(pToken->params.size() != 2) + throw ParserException(pToken->line, pToken->column, "TAG directives must have exactly two arguments"); - std::string handle = params[0], prefix = params[1]; + std::string handle = pToken->params[0], prefix = pToken->params[1]; m_state.tags[handle] = prefix; } diff --git a/parser.h b/parser.h index 33c24c1..2b9b8ea 100644 --- a/parser.h +++ b/parser.h @@ -9,8 +9,8 @@ namespace YAML { - class Node; class Scanner; + struct Token; class Parser { @@ -26,9 +26,9 @@ namespace YAML private: void ParseDirectives(); - void HandleDirective(const std::string& name, const std::vector & params); - void HandleYamlDirective(const std::vector & params); - void HandleTagDirective(const std::vector & params); + void HandleDirective(Token *pToken); + void HandleYamlDirective(Token *pToken); + void HandleTagDirective(Token *pToken); private: Scanner *m_pScanner; diff --git a/scanner.cpp b/scanner.cpp index a231b9d..cfa330d 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -157,7 +157,7 @@ namespace YAML return ScanPlainScalar(); // don't know what it is! - throw UnknownToken(); + throw ParserException(INPUT.line, INPUT.column, "unknown token"); } // ScanToNextToken @@ -256,9 +256,9 @@ namespace YAML m_indents.push(column); Token *pToken = 0; if(sequence) - pToken = new Token(TT_BLOCK_SEQ_START); + pToken = new Token(TT_BLOCK_SEQ_START, INPUT.line, INPUT.column); else - pToken = new Token(TT_BLOCK_MAP_START); + pToken = new Token(TT_BLOCK_MAP_START, INPUT.line, INPUT.column); m_tokens.push(pToken); return pToken; @@ -276,7 +276,7 @@ namespace YAML // now pop away while(!m_indents.empty() && m_indents.top() > column) { m_indents.pop(); - m_tokens.push(new Token(TT_BLOCK_END)); + m_tokens.push(new Token(TT_BLOCK_END, INPUT.line, INPUT.column)); } } } diff --git a/scanscalar.cpp b/scanscalar.cpp index 76b0238..c83c091 100644 --- a/scanscalar.cpp +++ b/scanscalar.cpp @@ -35,7 +35,7 @@ namespace YAML if(params.onDocIndicator == BREAK) break; else if(params.onDocIndicator == THROW) - throw IllegalDocIndicator(); + throw ParserException(INPUT.line, INPUT.column, "illegal document indicator in scalar"); } foundNonEmptyLine = true; @@ -61,7 +61,7 @@ namespace YAML // eof? if we're looking to eat something, then we throw if(INPUT.peek() == EOF) { if(params.eatEnd) - throw IllegalEOF(); + throw ParserException(INPUT.line, INPUT.column, "illegal EOF in scalar"); break; } @@ -97,7 +97,7 @@ namespace YAML while(Exp::Blank.Matches(INPUT)) { // we check for tabs that masquerade as indentation if(INPUT.peek() == '\t'&& INPUT.column < params.indent && params.onTabInIndentation == THROW) - throw IllegalTabInIndentation(); + throw ParserException(INPUT.line, INPUT.column, "illegal tab when looking for indentation"); if(!params.eatLeadingWhitespace) break; diff --git a/scantoken.cpp b/scantoken.cpp index 05bae3d..04dbfa8 100644 --- a/scantoken.cpp +++ b/scantoken.cpp @@ -3,6 +3,7 @@ #include "exceptions.h" #include "exp.h" #include "scanscalar.h" +#include namespace YAML { @@ -22,7 +23,8 @@ namespace YAML m_simpleKeyAllowed = false; - // eat indicator + // store pos and eat indicator + int line = INPUT.line, column = INPUT.column; INPUT.eat(1); // read name @@ -47,7 +49,7 @@ namespace YAML params.push_back(param); } - Token *pToken = new Token(TT_DIRECTIVE); + Token *pToken = new Token(TT_DIRECTIVE, line, column); pToken->value = name; pToken->params = params; m_tokens.push(pToken); @@ -61,8 +63,9 @@ namespace YAML m_simpleKeyAllowed = false; // eat + int line = INPUT.line, column = INPUT.column; INPUT.eat(3); - m_tokens.push(new Token(TT_DOC_START)); + m_tokens.push(new Token(TT_DOC_START, line, column)); } // DocEnd @@ -73,8 +76,9 @@ namespace YAML m_simpleKeyAllowed = false; // eat + int line = INPUT.line, column = INPUT.column; INPUT.eat(3); - m_tokens.push(new Token(TT_DOC_END)); + m_tokens.push(new Token(TT_DOC_END, line, column)); } // FlowStart @@ -86,24 +90,26 @@ namespace YAML m_simpleKeyAllowed = true; // eat + int line = INPUT.line, column = INPUT.column; char ch = INPUT.get(); TOKEN_TYPE type = (ch == Keys::FlowSeqStart ? TT_FLOW_SEQ_START : TT_FLOW_MAP_START); - m_tokens.push(new Token(type)); + m_tokens.push(new Token(type, line, column)); } // FlowEnd void Scanner::ScanFlowEnd() { if(m_flowLevel == 0) - throw IllegalFlowEnd(); + throw ParserException(INPUT.line, INPUT.column, "illegal flow end"); m_flowLevel--; m_simpleKeyAllowed = false; // eat + int line = INPUT.line, column = INPUT.column; char ch = INPUT.get(); TOKEN_TYPE type = (ch == Keys::FlowSeqEnd ? TT_FLOW_SEQ_END : TT_FLOW_MAP_END); - m_tokens.push(new Token(type)); + m_tokens.push(new Token(type, line, column)); } // FlowEntry @@ -112,8 +118,9 @@ namespace YAML m_simpleKeyAllowed = true; // eat + int line = INPUT.line, column = INPUT.column; INPUT.eat(1); - m_tokens.push(new Token(TT_FLOW_ENTRY)); + m_tokens.push(new Token(TT_FLOW_ENTRY, line, column)); } // BlockEntry @@ -121,18 +128,19 @@ namespace YAML { // we better be in the block context! if(m_flowLevel > 0) - throw IllegalBlockEntry(); + throw ParserException(INPUT.line, INPUT.column, "illegal block entry"); // can we put it here? if(!m_simpleKeyAllowed) - throw IllegalBlockEntry(); + throw ParserException(INPUT.line, INPUT.column, "illegal block entry"); PushIndentTo(INPUT.column, true); m_simpleKeyAllowed = true; // eat + int line = INPUT.line, column = INPUT.column; INPUT.eat(1); - m_tokens.push(new Token(TT_BLOCK_ENTRY)); + m_tokens.push(new Token(TT_BLOCK_ENTRY, line, column)); } // Key @@ -141,7 +149,7 @@ namespace YAML // handle keys diffently in the block context (and manage indents) if(m_flowLevel == 0) { if(!m_simpleKeyAllowed) - throw IllegalMapKey(); + throw ParserException(INPUT.line, INPUT.column, "illegal map key"); PushIndentTo(INPUT.column, false); } @@ -153,8 +161,9 @@ namespace YAML m_simpleKeyAllowed = false; // eat + int line = INPUT.line, column = INPUT.column; INPUT.eat(1); - m_tokens.push(new Token(TT_KEY)); + m_tokens.push(new Token(TT_KEY, line, column)); } // Value @@ -168,7 +177,7 @@ namespace YAML // handle values diffently in the block context (and manage indents) if(m_flowLevel == 0) { if(!m_simpleKeyAllowed) - throw IllegalMapValue(); + throw ParserException(INPUT.line, INPUT.column, "illegal map value"); PushIndentTo(INPUT.column, false); } @@ -181,8 +190,9 @@ namespace YAML } // eat + int line = INPUT.line, column = INPUT.column; INPUT.eat(1); - m_tokens.push(new Token(TT_VALUE)); + m_tokens.push(new Token(TT_VALUE, line, column)); } // AnchorOrAlias @@ -197,6 +207,7 @@ namespace YAML m_simpleKeyAllowed = false; // eat the indicator + int line = INPUT.line, column = INPUT.column; char indicator = INPUT.get(); alias = (indicator == Keys::Alias); @@ -205,15 +216,24 @@ namespace YAML name += INPUT.get(); // we need to have read SOMETHING! - if(name.empty()) - throw AnchorNotFound(); + if(name.empty()) { + std::stringstream msg; + msg << (alias ? "alias" : "anchor"); + msg << " not found after "; + msg << (alias ? "*" : "&"); + throw ParserException(INPUT.line, INPUT.column, msg.str()); + } // and needs to end correctly - if(INPUT.peek() != EOF && !Exp::AnchorEnd.Matches(INPUT)) - throw IllegalCharacterInAnchor(); + if(INPUT.peek() != EOF && !Exp::AnchorEnd.Matches(INPUT)) { + std::stringstream msg; + msg << "illegal character found while scanning "; + msg << (alias ? "alias" : "anchor"); + throw ParserException(INPUT.line, INPUT.column, msg.str()); + } // and we're done - Token *pToken = new Token(alias ? TT_ALIAS : TT_ANCHOR); + Token *pToken = new Token(alias ? TT_ALIAS : TT_ANCHOR, line, column); pToken->value = name; m_tokens.push(pToken); } @@ -229,6 +249,7 @@ namespace YAML m_simpleKeyAllowed = false; // eat the indicator + int line = INPUT.line, column = INPUT.column; handle += INPUT.get(); // read the handle @@ -249,7 +270,7 @@ namespace YAML handle = "!"; } - Token *pToken = new Token(TT_TAG); + Token *pToken = new Token(TT_TAG, line, column); pToken->value = handle; pToken->params.push_back(suffix); m_tokens.push(pToken); @@ -276,6 +297,7 @@ namespace YAML if(m_simpleKeyAllowed) InsertSimpleKey(); + int line = INPUT.line, column = INPUT.column; scalar = ScanScalar(INPUT, params); // can have a simple key only if we ended the scalar by starting a new line @@ -284,9 +306,9 @@ namespace YAML // finally, we can't have any colons in a scalar, so if we ended on a colon, there // had better be a break after it if(Exp::IllegalColonInScalar.Matches(INPUT)) - throw IllegalScalar(); + throw ParserException(INPUT.line, INPUT.column, "illegal character in scalar"); - Token *pToken = new Token(TT_SCALAR); + Token *pToken = new Token(TT_SCALAR, line, column); pToken->value = scalar; m_tokens.push(pToken); } @@ -316,10 +338,11 @@ namespace YAML if(m_simpleKeyAllowed) InsertSimpleKey(); + int line = INPUT.line, column = INPUT.column; scalar = ScanScalar(INPUT, params); m_simpleKeyAllowed = false; - Token *pToken = new Token(TT_SCALAR); + Token *pToken = new Token(TT_SCALAR, line, column); pToken->value = scalar; m_tokens.push(pToken); } @@ -337,6 +360,7 @@ namespace YAML params.detectIndent = true; // eat block indicator ('|' or '>') + int line = INPUT.line, column = INPUT.column; char indicator = INPUT.get(); params.fold = (indicator == Keys::FoldedScalar); @@ -350,7 +374,7 @@ namespace YAML params.chomp = STRIP; else if(Exp::Digit.Matches(ch)) { if(ch == '0') - throw ZeroIndentationInBlockScalar(); + throw ParserException(INPUT.line, INPUT.column, "cannot set zero indentation for a block scalar"); params.indent = ch - '0'; params.detectIndent = false; @@ -368,7 +392,7 @@ namespace YAML // if it's not a line break, then we ran into a bad character inline if(INPUT && !Exp::Break.Matches(INPUT)) - throw UnexpectedCharacterInBlockScalar(); + throw ParserException(INPUT.line, INPUT.column, "unexpected character in block scalar"); // set the initial indentation if(m_indents.top() >= 0) @@ -383,7 +407,7 @@ namespace YAML // simple keys always ok after block scalars (since we're gonna start a new line anyways) m_simpleKeyAllowed = true; - Token *pToken = new Token(TT_SCALAR); + Token *pToken = new Token(TT_SCALAR, line, column); pToken->value = scalar; m_tokens.push(pToken); } diff --git a/sequence.cpp b/sequence.cpp index 1ec82de..b4cd495 100644 --- a/sequence.cpp +++ b/sequence.cpp @@ -68,10 +68,10 @@ namespace YAML while(1) { Token *pToken = pScanner->PeekNextToken(); if(!pToken) - throw SeqEndNotFound(); + throw ParserException(-1, -1, "end of sequence not found"); if(pToken->type != TT_BLOCK_ENTRY && pToken->type != TT_BLOCK_END) - throw SeqEndNotFound(); + throw ParserException(pToken->line, pToken->column, "end of sequence not found"); pScanner->PopNextToken(); if(pToken->type == TT_BLOCK_END) @@ -111,7 +111,7 @@ namespace YAML while(1) { Token *pToken = pScanner->PeekNextToken(); if(!pToken) - throw SeqEndNotFound(); + throw ParserException(-1, -1, "end of sequence flow not found"); // first check for end if(pToken->type == TT_FLOW_SEQ_END) { @@ -129,7 +129,7 @@ namespace YAML if(pToken->type == TT_FLOW_ENTRY) pScanner->EatNextToken(); else if(pToken->type != TT_FLOW_SEQ_END) - throw SeqEndNotFound(); + throw ParserException(pToken->line, pToken->column, "end of sequence flow not found"); } } diff --git a/simplekey.cpp b/simplekey.cpp index 3f17265..040c398 100644 --- a/simplekey.cpp +++ b/simplekey.cpp @@ -21,7 +21,7 @@ namespace YAML void Scanner::SimpleKey::Invalidate() { if(required) - throw RequiredSimpleKeyNotFound(); + throw ParserException(line, column, "required simple key not found"); if(pMapStart) pMapStart->status = TS_INVALID; @@ -44,7 +44,7 @@ namespace YAML // key.required = true; // TODO: is this correct? // then add the (now unverified) key - key.pKey = new Token(TT_KEY); + key.pKey = new Token(TT_KEY, INPUT.line, INPUT.column); key.pKey->status = TS_UNVERIFIED; m_tokens.push(key.pKey); diff --git a/tests.cpp b/tests.cpp index 01df50b..98b5a3b 100644 --- a/tests.cpp +++ b/tests.cpp @@ -71,7 +71,8 @@ namespace YAML fout << secondTry << std::endl; return false; - } catch(Exception&) { + } catch(ParserException& e) { + std::cout << file << " (line " << e.line + 1 << ", col " << e.column + 1 << "): " << e.msg << std::endl; return false; } diff --git a/token.h b/token.h index 17bd20d..3606fd0 100644 --- a/token.h +++ b/token.h @@ -50,7 +50,7 @@ namespace YAML }; struct Token { - Token(TOKEN_TYPE type_): status(TS_VALID), type(type_) {} + Token(TOKEN_TYPE type_, int line_, int column_): status(TS_VALID), type(type_), line(line_), column(column_) {} friend std::ostream& operator << (std::ostream& out, const Token& token) { out << TokenNames[token.type] << ": " << token.value; @@ -61,6 +61,7 @@ namespace YAML TOKEN_STATUS status; TOKEN_TYPE type; + int line, column; std::string value; std::vector params; }; From 5d5651861d2430e4e8b367bed9418b2bc7005d50 Mon Sep 17 00:00:00 2001 From: beder Date: Tue, 8 Jul 2008 06:06:24 +0000 Subject: [PATCH 047/295] Added some exceptions for directives. --- node.cpp | 22 +++++++++++----------- parser.cpp | 12 ++++++++---- tests.cpp | 3 +-- tests/directives.yaml | 5 +++++ 4 files changed, 25 insertions(+), 17 deletions(-) create mode 100644 tests/directives.yaml diff --git a/node.cpp b/node.cpp index c31fe96..78a2793 100644 --- a/node.cpp +++ b/node.cpp @@ -83,10 +83,10 @@ namespace YAML void Node::ParseTag(Scanner *pScanner, const ParserState& state) { - if(m_tag != "") - return; // TODO: throw - Token *pToken = pScanner->PeekNextToken(); + if(m_tag != "") + throw ParserException(pToken->line, pToken->column, "cannot assign multiple tags to the same node"); + m_tag = state.TranslateTag(pToken->value); for(unsigned i=0;iparams.size();i++) @@ -96,10 +96,10 @@ namespace YAML void Node::ParseAnchor(Scanner *pScanner, const ParserState& state) { - if(m_anchor != "") - return; // TODO: throw - Token *pToken = pScanner->PeekNextToken(); + if(m_anchor != "") + throw ParserException(pToken->line, pToken->column, "cannot assign multiple anchors to the same node"); + m_anchor = pToken->value; m_alias = false; pScanner->PopNextToken(); @@ -107,12 +107,12 @@ namespace YAML void Node::ParseAlias(Scanner *pScanner, const ParserState& state) { - if(m_anchor != "") - return; // TODO: throw - if(m_tag != "") - return; // TODO: throw (aliases can't have any content, *including* tags) - Token *pToken = pScanner->PeekNextToken(); + if(m_anchor != "") + throw ParserException(pToken->line, pToken->column, "cannot assign multiple aliases to the same node"); + if(m_tag != "") + throw ParserException(pToken->line, pToken->column, "aliases can't have any content, *including* tags"); + m_anchor = pToken->value; m_alias = true; pScanner->PopNextToken(); diff --git a/parser.cpp b/parser.cpp index 82935d1..f27a344 100644 --- a/parser.cpp +++ b/parser.cpp @@ -96,13 +96,17 @@ namespace YAML str >> m_state.version.major; str.get(); str >> m_state.version.minor; - if(!str) - throw ParserException(pToken->line, pToken->column, "bad YAML directive"); - // TODO: or throw if there are any more characters in the stream? + if(!str || str.peek() != EOF) + throw ParserException(pToken->line, pToken->column, "bad YAML version: " + pToken->params[0]); - // TODO: throw on major > 1? warning on major == 1, minor > 2? + if(m_state.version.major > 1) + throw ParserException(pToken->line, pToken->column, "YAML major version > 1"); + + // TODO: warning on major == 1, minor > 2? } + // HandleTagDirective + // . Should be of the form 'handle prefix', where 'handle' is converted to 'prefix' in the file. void Parser::HandleTagDirective(Token *pToken) { if(pToken->params.size() != 2) diff --git a/tests.cpp b/tests.cpp index 98b5a3b..ad41f67 100644 --- a/tests.cpp +++ b/tests.cpp @@ -16,6 +16,7 @@ namespace YAML files.push_back("tests/simple.yaml"); files.push_back("tests/mixed.yaml"); files.push_back("tests/scalars.yaml"); + files.push_back("tests/directives.yaml"); bool passed = true; for(unsigned i=0;i Date: Tue, 8 Jul 2008 18:34:26 +0000 Subject: [PATCH 048/295] Removed the (unused) 'required' flag from simple keys (the parser should take care of this, not the scanner). --- scanner.h | 1 - simplekey.cpp | 7 +------ yaml-reader.vcproj | 16 ++++++++++++++++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/scanner.h b/scanner.h index 48ba219..63a911b 100644 --- a/scanner.h +++ b/scanner.h @@ -45,7 +45,6 @@ namespace YAML void Invalidate(); int pos, line, column, flowLevel; - bool required; Token *pMapStart, *pKey; }; diff --git a/simplekey.cpp b/simplekey.cpp index 040c398..a5e6bc3 100644 --- a/simplekey.cpp +++ b/simplekey.cpp @@ -6,7 +6,7 @@ namespace YAML { Scanner::SimpleKey::SimpleKey(int pos_, int line_, int column_, int flowLevel_) - : pos(pos_), line(line_), column(column_), flowLevel(flowLevel_), required(false), pMapStart(0), pKey(0) + : pos(pos_), line(line_), column(column_), flowLevel(flowLevel_), pMapStart(0), pKey(0) { } @@ -20,9 +20,6 @@ namespace YAML void Scanner::SimpleKey::Invalidate() { - if(required) - throw ParserException(line, column, "required simple key not found"); - if(pMapStart) pMapStart->status = TS_INVALID; if(pKey) @@ -40,8 +37,6 @@ namespace YAML key.pMapStart = PushIndentTo(INPUT.column, false); if(key.pMapStart) key.pMapStart->status = TS_UNVERIFIED; -// else -// key.required = true; // TODO: is this correct? // then add the (now unverified) key key.pKey = new Token(TT_KEY, INPUT.line, INPUT.column); diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index 5239b09..b708279 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -329,6 +329,22 @@ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > + + + + + + + + From 0b2e0dd32b8865d315cda23dba5aab00d89e944a Mon Sep 17 00:00:00 2001 From: beder Date: Tue, 8 Jul 2008 20:31:48 +0000 Subject: [PATCH 049/295] Centralized the error messages to one location. --- exceptions.h | 35 +++++++++++++++++++++++++++++++++++ exp.cpp | 7 +++---- map.cpp | 10 +++++----- node.cpp | 8 ++++---- parser.cpp | 8 ++++---- scanner.cpp | 2 +- scanscalar.cpp | 6 +++--- scantoken.cpp | 33 ++++++++++++--------------------- sequence.cpp | 8 ++++---- 9 files changed, 71 insertions(+), 46 deletions(-) diff --git a/exceptions.h b/exceptions.h index 017b0b1..f3a27f0 100644 --- a/exceptions.h +++ b/exceptions.h @@ -18,4 +18,39 @@ namespace YAML // representation exceptions class InvalidScalar: public RepresentationException {}; class BadDereference: public RepresentationException {}; + + // error messages + namespace ErrorMsg + { + const std::string YAML_DIRECTIVE_ARGS = "YAML directives must have exactly one argument"; + const std::string YAML_VERSION = "bad YAML version: "; + const std::string YAML_MAJOR_VERSION = "YAML major version too large"; + const std::string TAG_DIRECTIVE_ARGS = "TAG directives must have exactly two arguments"; + const std::string END_OF_MAP = "end of map not found"; + const std::string END_OF_MAP_FLOW = "end of map flow not found"; + const std::string END_OF_SEQ = "end of sequence not found"; + const std::string END_OF_SEQ_FLOW = "end of sequence flow not found"; + const std::string MULTIPLE_TAGS = "cannot assign multiple tags to the same node"; + const std::string MULTIPLE_ANCHORS = "cannot assign multiple anchors to the same node"; + const std::string MULTIPLE_ALIASES = "cannot assign multiple aliases to the same node"; + const std::string ALIAS_CONTENT = "aliases can't have any content, *including* tags"; + const std::string INVALID_HEX = "bad character found while scanning hex number"; + const std::string INVALID_UNICODE = "invalid unicode: "; + const std::string INVALID_ESCAPE = "unknown escape character: "; + const std::string UNKNOWN_TOKEN = "unknown token"; + const std::string DOC_IN_SCALAR = "illegal document indicator in scalar"; + const std::string EOF_IN_SCALAR = "illegal EOF in scalar"; + const std::string CHAR_IN_SCALAR = "illegal character in scalar"; + const std::string TAB_IN_INDENTATION = "illegal tab when looking for indentation"; + const std::string FLOW_END = "illegal flow end"; + const std::string BLOCK_ENTRY = "illegal block entry"; + const std::string MAP_KEY = "illegal map key"; + const std::string MAP_VALUE = "illegal map value"; + const std::string ALIAS_NOT_FOUND = "alias not found after *"; + const std::string ANCHOR_NOT_FOUND = "anchor not found after &"; + const std::string CHAR_IN_ALIAS = "illegal character found while scanning alias"; + const std::string CHAR_IN_ANCHOR = "illegal character found while scanning anchor"; + const std::string ZERO_INDENT_IN_BLOCK = "cannot set zero indentation for a block scalar"; + const std::string CHAR_IN_BLOCK = "unexpected character in block scalar"; + } } diff --git a/exp.cpp b/exp.cpp index f766de6..05b1b24 100644 --- a/exp.cpp +++ b/exp.cpp @@ -19,7 +19,7 @@ namespace YAML else if('0' <= ch && ch <= '9') digit = ch - '0'; else - throw ParserException(line, column, "bad character found while scanning hex number"); + throw ParserException(line, column, ErrorMsg::INVALID_HEX); value = (value << 4) + digit; } @@ -48,7 +48,7 @@ namespace YAML // legal unicode? if((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) { std::stringstream msg; - msg << "invalid unicode: " << value; + msg << ErrorMsg::INVALID_UNICODE << value; throw ParserException(in.line, in.column, msg.str()); } @@ -106,8 +106,7 @@ namespace YAML } std::stringstream msg; - msg << "unknown escape character: " << ch; - throw ParserException(in.line, in.column, msg.str()); + throw ParserException(in.line, in.column, ErrorMsg::INVALID_ESCAPE + ch); } } } diff --git a/map.cpp b/map.cpp index 0687f34..19a3cb9 100644 --- a/map.cpp +++ b/map.cpp @@ -57,10 +57,10 @@ namespace YAML while(1) { Token *pToken = pScanner->PeekNextToken(); if(!pToken) - throw ParserException(-1, -1, "end of map not found"); + throw ParserException(-1, -1, ErrorMsg::END_OF_MAP); if(pToken->type != TT_KEY && pToken->type != TT_BLOCK_END) - throw ParserException(pToken->line, pToken->column, "end of map not found"); + throw ParserException(pToken->line, pToken->column, ErrorMsg::END_OF_MAP); pScanner->PopNextToken(); if(pToken->type == TT_BLOCK_END) @@ -96,7 +96,7 @@ namespace YAML while(1) { Token *pToken = pScanner->PeekNextToken(); if(!pToken) - throw ParserException(-1, -1, "end of map flow not found"); + throw ParserException(-1, -1, ErrorMsg::END_OF_MAP_FLOW); // first check for end if(pToken->type == TT_FLOW_MAP_END) { @@ -106,7 +106,7 @@ namespace YAML // now it better be a key if(pToken->type != TT_KEY) - throw ParserException(pToken->line, pToken->column, "end of map flow not found"); + throw ParserException(pToken->line, pToken->column, ErrorMsg::END_OF_MAP_FLOW); pScanner->PopNextToken(); @@ -128,7 +128,7 @@ namespace YAML if(pToken->type == TT_FLOW_ENTRY) pScanner->EatNextToken(); else if(pToken->type != TT_FLOW_MAP_END) - throw ParserException(pToken->line, pToken->column, "end of map flow not found"); + throw ParserException(pToken->line, pToken->column, ErrorMsg::END_OF_MAP_FLOW); m_data[pKey] = pValue; } catch(Exception& e) { diff --git a/node.cpp b/node.cpp index 78a2793..c878e9a 100644 --- a/node.cpp +++ b/node.cpp @@ -85,7 +85,7 @@ namespace YAML { Token *pToken = pScanner->PeekNextToken(); if(m_tag != "") - throw ParserException(pToken->line, pToken->column, "cannot assign multiple tags to the same node"); + throw ParserException(pToken->line, pToken->column, ErrorMsg::MULTIPLE_TAGS); m_tag = state.TranslateTag(pToken->value); @@ -98,7 +98,7 @@ namespace YAML { Token *pToken = pScanner->PeekNextToken(); if(m_anchor != "") - throw ParserException(pToken->line, pToken->column, "cannot assign multiple anchors to the same node"); + throw ParserException(pToken->line, pToken->column, ErrorMsg::MULTIPLE_ANCHORS); m_anchor = pToken->value; m_alias = false; @@ -109,9 +109,9 @@ namespace YAML { Token *pToken = pScanner->PeekNextToken(); if(m_anchor != "") - throw ParserException(pToken->line, pToken->column, "cannot assign multiple aliases to the same node"); + throw ParserException(pToken->line, pToken->column, ErrorMsg::MULTIPLE_ALIASES); if(m_tag != "") - throw ParserException(pToken->line, pToken->column, "aliases can't have any content, *including* tags"); + throw ParserException(pToken->line, pToken->column, ErrorMsg::ALIAS_CONTENT); m_anchor = pToken->value; m_alias = true; diff --git a/parser.cpp b/parser.cpp index f27a344..0f79d4f 100644 --- a/parser.cpp +++ b/parser.cpp @@ -90,17 +90,17 @@ namespace YAML void Parser::HandleYamlDirective(Token *pToken) { if(pToken->params.size() != 1) - throw ParserException(pToken->line, pToken->column, "YAML directives must have exactly one argument"); + throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_DIRECTIVE_ARGS); std::stringstream str(pToken->params[0]); str >> m_state.version.major; str.get(); str >> m_state.version.minor; if(!str || str.peek() != EOF) - throw ParserException(pToken->line, pToken->column, "bad YAML version: " + pToken->params[0]); + throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_VERSION + pToken->params[0]); if(m_state.version.major > 1) - throw ParserException(pToken->line, pToken->column, "YAML major version > 1"); + throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_MAJOR_VERSION); // TODO: warning on major == 1, minor > 2? } @@ -110,7 +110,7 @@ namespace YAML void Parser::HandleTagDirective(Token *pToken) { if(pToken->params.size() != 2) - throw ParserException(pToken->line, pToken->column, "TAG directives must have exactly two arguments"); + throw ParserException(pToken->line, pToken->column, ErrorMsg::TAG_DIRECTIVE_ARGS); std::string handle = pToken->params[0], prefix = pToken->params[1]; m_state.tags[handle] = prefix; diff --git a/scanner.cpp b/scanner.cpp index cfa330d..110d1a3 100644 --- a/scanner.cpp +++ b/scanner.cpp @@ -157,7 +157,7 @@ namespace YAML return ScanPlainScalar(); // don't know what it is! - throw ParserException(INPUT.line, INPUT.column, "unknown token"); + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::UNKNOWN_TOKEN); } // ScanToNextToken diff --git a/scanscalar.cpp b/scanscalar.cpp index c83c091..c2cf2b9 100644 --- a/scanscalar.cpp +++ b/scanscalar.cpp @@ -35,7 +35,7 @@ namespace YAML if(params.onDocIndicator == BREAK) break; else if(params.onDocIndicator == THROW) - throw ParserException(INPUT.line, INPUT.column, "illegal document indicator in scalar"); + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::DOC_IN_SCALAR); } foundNonEmptyLine = true; @@ -61,7 +61,7 @@ namespace YAML // eof? if we're looking to eat something, then we throw if(INPUT.peek() == EOF) { if(params.eatEnd) - throw ParserException(INPUT.line, INPUT.column, "illegal EOF in scalar"); + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::EOF_IN_SCALAR); break; } @@ -97,7 +97,7 @@ namespace YAML while(Exp::Blank.Matches(INPUT)) { // we check for tabs that masquerade as indentation if(INPUT.peek() == '\t'&& INPUT.column < params.indent && params.onTabInIndentation == THROW) - throw ParserException(INPUT.line, INPUT.column, "illegal tab when looking for indentation"); + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::TAB_IN_INDENTATION); if(!params.eatLeadingWhitespace) break; diff --git a/scantoken.cpp b/scantoken.cpp index 04dbfa8..7a12c9a 100644 --- a/scantoken.cpp +++ b/scantoken.cpp @@ -100,7 +100,7 @@ namespace YAML void Scanner::ScanFlowEnd() { if(m_flowLevel == 0) - throw ParserException(INPUT.line, INPUT.column, "illegal flow end"); + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::FLOW_END); m_flowLevel--; m_simpleKeyAllowed = false; @@ -128,11 +128,11 @@ namespace YAML { // we better be in the block context! if(m_flowLevel > 0) - throw ParserException(INPUT.line, INPUT.column, "illegal block entry"); + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::BLOCK_ENTRY); // can we put it here? if(!m_simpleKeyAllowed) - throw ParserException(INPUT.line, INPUT.column, "illegal block entry"); + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::BLOCK_ENTRY); PushIndentTo(INPUT.column, true); m_simpleKeyAllowed = true; @@ -149,7 +149,7 @@ namespace YAML // handle keys diffently in the block context (and manage indents) if(m_flowLevel == 0) { if(!m_simpleKeyAllowed) - throw ParserException(INPUT.line, INPUT.column, "illegal map key"); + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::MAP_KEY); PushIndentTo(INPUT.column, false); } @@ -177,7 +177,7 @@ namespace YAML // handle values diffently in the block context (and manage indents) if(m_flowLevel == 0) { if(!m_simpleKeyAllowed) - throw ParserException(INPUT.line, INPUT.column, "illegal map value"); + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::MAP_VALUE); PushIndentTo(INPUT.column, false); } @@ -216,21 +216,12 @@ namespace YAML name += INPUT.get(); // we need to have read SOMETHING! - if(name.empty()) { - std::stringstream msg; - msg << (alias ? "alias" : "anchor"); - msg << " not found after "; - msg << (alias ? "*" : "&"); - throw ParserException(INPUT.line, INPUT.column, msg.str()); - } + if(name.empty()) + throw ParserException(INPUT.line, INPUT.column, alias ? ErrorMsg::ALIAS_NOT_FOUND : ErrorMsg::ANCHOR_NOT_FOUND); // and needs to end correctly - if(INPUT.peek() != EOF && !Exp::AnchorEnd.Matches(INPUT)) { - std::stringstream msg; - msg << "illegal character found while scanning "; - msg << (alias ? "alias" : "anchor"); - throw ParserException(INPUT.line, INPUT.column, msg.str()); - } + if(INPUT.peek() != EOF && !Exp::AnchorEnd.Matches(INPUT)) + throw ParserException(INPUT.line, INPUT.column, alias ? ErrorMsg::CHAR_IN_ALIAS : ErrorMsg::CHAR_IN_ANCHOR); // and we're done Token *pToken = new Token(alias ? TT_ALIAS : TT_ANCHOR, line, column); @@ -306,7 +297,7 @@ namespace YAML // finally, we can't have any colons in a scalar, so if we ended on a colon, there // had better be a break after it if(Exp::IllegalColonInScalar.Matches(INPUT)) - throw ParserException(INPUT.line, INPUT.column, "illegal character in scalar"); + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::CHAR_IN_SCALAR); Token *pToken = new Token(TT_SCALAR, line, column); pToken->value = scalar; @@ -374,7 +365,7 @@ namespace YAML params.chomp = STRIP; else if(Exp::Digit.Matches(ch)) { if(ch == '0') - throw ParserException(INPUT.line, INPUT.column, "cannot set zero indentation for a block scalar"); + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::ZERO_INDENT_IN_BLOCK); params.indent = ch - '0'; params.detectIndent = false; @@ -392,7 +383,7 @@ namespace YAML // if it's not a line break, then we ran into a bad character inline if(INPUT && !Exp::Break.Matches(INPUT)) - throw ParserException(INPUT.line, INPUT.column, "unexpected character in block scalar"); + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::CHAR_IN_BLOCK); // set the initial indentation if(m_indents.top() >= 0) diff --git a/sequence.cpp b/sequence.cpp index b4cd495..8c1e3ca 100644 --- a/sequence.cpp +++ b/sequence.cpp @@ -68,10 +68,10 @@ namespace YAML while(1) { Token *pToken = pScanner->PeekNextToken(); if(!pToken) - throw ParserException(-1, -1, "end of sequence not found"); + throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ); if(pToken->type != TT_BLOCK_ENTRY && pToken->type != TT_BLOCK_END) - throw ParserException(pToken->line, pToken->column, "end of sequence not found"); + throw ParserException(pToken->line, pToken->column, ErrorMsg::END_OF_SEQ); pScanner->PopNextToken(); if(pToken->type == TT_BLOCK_END) @@ -111,7 +111,7 @@ namespace YAML while(1) { Token *pToken = pScanner->PeekNextToken(); if(!pToken) - throw ParserException(-1, -1, "end of sequence flow not found"); + throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ_FLOW); // first check for end if(pToken->type == TT_FLOW_SEQ_END) { @@ -129,7 +129,7 @@ namespace YAML if(pToken->type == TT_FLOW_ENTRY) pScanner->EatNextToken(); else if(pToken->type != TT_FLOW_SEQ_END) - throw ParserException(pToken->line, pToken->column, "end of sequence flow not found"); + throw ParserException(pToken->line, pToken->column, ErrorMsg::END_OF_SEQ_FLOW); } } From e6aeb45d09c304c99ff14167d3170972cf589830 Mon Sep 17 00:00:00 2001 From: beder Date: Thu, 10 Jul 2008 00:23:25 +0000 Subject: [PATCH 050/295] Switched from moving the cursor forward (in Regex) to ignoring (this handles newlines properly). Updated some of the character-in-scalar rules. --- exp.h | 9 ++++----- regex.cpp | 2 +- scantoken.cpp | 9 ++++----- tests/scalars.yaml | 13 ++++++++++++- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/exp.h b/exp.h index 652e2bd..530973e 100644 --- a/exp.h +++ b/exp.h @@ -29,7 +29,7 @@ namespace YAML const RegEx BlockEntry = RegEx('-') + (BlankOrBreak || RegEx(EOF)); const RegEx Key = RegEx('?'), KeyInFlow = RegEx('?') + BlankOrBreak; - const RegEx Value = RegEx(':'), + const RegEx Value = RegEx(':') + BlankOrBreak, ValueInFlow = RegEx(':') + BlankOrBreak; const RegEx Comment = RegEx('#'); const RegEx AnchorEnd = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak; @@ -38,12 +38,11 @@ namespace YAML // . Cannot start with a blank. // . Can never start with any of , [ ] { } # & * ! | > \' \" % @ ` // . In the block context - ? : must be not be followed with a space. - // . In the flow context ? : are illegal and - must not be followed with a space. + // . In the flow context ? is illegal and : and - must not be followed with a space. const RegEx PlainScalar = !(BlankOrBreak || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:", REGEX_OR) + Blank)), - PlainScalarInFlow = !(BlankOrBreak || RegEx("?:,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx('-') + Blank)); - const RegEx IllegalColonInScalar = RegEx(':') + !BlankOrBreak; + PlainScalarInFlow = !(BlankOrBreak || RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-:", REGEX_OR) + Blank)); const RegEx EndScalar = RegEx(':') + BlankOrBreak, - EndScalarInFlow = (RegEx(':') + BlankOrBreak) || RegEx(",:?[]{}", REGEX_OR); + EndScalarInFlow = (RegEx(':') + BlankOrBreak) || RegEx(",?[]{}", REGEX_OR); const RegEx EscSingleQuote = RegEx("\'\'"); const RegEx EscBreak = RegEx('\\') + Break; diff --git a/regex.cpp b/regex.cpp index 1da6289..e7f93e1 100644 --- a/regex.cpp +++ b/regex.cpp @@ -283,7 +283,7 @@ namespace YAML return -1; offset += n; - in.seekg(n, std::ios_base::cur); + in.ignore(n); } return offset; diff --git a/scantoken.cpp b/scantoken.cpp index 7a12c9a..5704a0a 100644 --- a/scantoken.cpp +++ b/scantoken.cpp @@ -274,7 +274,7 @@ namespace YAML // set up the scanning parameters ScanScalarParams params; - params.end = (m_flowLevel > 0 ? Exp::EndScalarInFlow : Exp::EndScalar) || (RegEx(' ') + Exp::Comment); + params.end = (m_flowLevel > 0 ? Exp::EndScalarInFlow : Exp::EndScalar) || (Exp::BlankOrBreak + Exp::Comment); params.eatEnd = false; params.indent = (m_flowLevel > 0 ? 0 : m_indents.top() + 1); params.fold = true; @@ -294,10 +294,9 @@ namespace YAML // can have a simple key only if we ended the scalar by starting a new line m_simpleKeyAllowed = params.leadingSpaces; - // finally, we can't have any colons in a scalar, so if we ended on a colon, there - // had better be a break after it - if(Exp::IllegalColonInScalar.Matches(INPUT)) - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::CHAR_IN_SCALAR); + // finally, check and see if we ended on an illegal character + //if(Exp::IllegalCharInScalar.Matches(INPUT)) + // throw ParserException(INPUT.line, INPUT.column, ErrorMsg::CHAR_IN_SCALAR); Token *pToken = new Token(TT_SCALAR, line, column); pToken->value = scalar; diff --git a/tests/scalars.yaml b/tests/scalars.yaml index 79c735a..ae0059a 100644 --- a/tests/scalars.yaml +++ b/tests/scalars.yaml @@ -21,4 +21,15 @@ that gets chomped. - >2 Here's a folded scalar - that starts with some indentation. \ No newline at end of file + that starts with some indentation. +- ::vector +- ": - ()" +- Up, up, and away! +- -123 +- http://example.com/foo#bar +# Inside flow collection: +- [ ::vector, + ": - ()", + "Up, up and away!", + -123, + http://example.com/foo#bar ] \ No newline at end of file From 516637fcdc693854e7e8cf56f20c9b629e9bcd87 Mon Sep 17 00:00:00 2001 From: beder Date: Mon, 14 Jul 2008 04:33:30 +0000 Subject: [PATCH 051/295] Moved all code to src/ and include/ directories. --- exceptions.h => include/exceptions.h | 0 ltnode.h => include/ltnode.h | 0 node.h => include/node.h | 0 parser.h => include/parser.h | 0 parserstate.h => include/parserstate.h | 0 content.cpp => src/content.cpp | 0 content.h => src/content.h | 0 exp.cpp => src/exp.cpp | 0 exp.h => src/exp.h | 0 iterator.cpp => src/iterator.cpp | 0 main.cpp => src/main.cpp | 0 map.cpp => src/map.cpp | 0 map.h => src/map.h | 0 node.cpp => src/node.cpp | 0 parser.cpp => src/parser.cpp | 0 parserstate.cpp => src/parserstate.cpp | 0 regex.cpp => src/regex.cpp | 0 regex.h => src/regex.h | 0 scalar.cpp => src/scalar.cpp | 0 scalar.h => src/scalar.h | 0 scanner.cpp => src/scanner.cpp | 0 scanner.h => src/scanner.h | 0 scanscalar.cpp => src/scanscalar.cpp | 0 scanscalar.h => src/scanscalar.h | 0 scantoken.cpp => src/scantoken.cpp | 0 sequence.cpp => src/sequence.cpp | 0 sequence.h => src/sequence.h | 0 simplekey.cpp => src/simplekey.cpp | 0 stream.cpp => src/stream.cpp | 0 stream.h => src/stream.h | 0 tests.cpp => src/tests.cpp | 0 tests.h => src/tests.h | 0 token.h => src/token.h | 0 tests/out.yaml | 8 +++ yaml-reader.vcproj | 68 +++++++++++++------------- 35 files changed, 43 insertions(+), 33 deletions(-) rename exceptions.h => include/exceptions.h (100%) rename ltnode.h => include/ltnode.h (100%) rename node.h => include/node.h (100%) rename parser.h => include/parser.h (100%) rename parserstate.h => include/parserstate.h (100%) rename content.cpp => src/content.cpp (100%) rename content.h => src/content.h (100%) rename exp.cpp => src/exp.cpp (100%) rename exp.h => src/exp.h (100%) rename iterator.cpp => src/iterator.cpp (100%) rename main.cpp => src/main.cpp (100%) rename map.cpp => src/map.cpp (100%) rename map.h => src/map.h (100%) rename node.cpp => src/node.cpp (100%) rename parser.cpp => src/parser.cpp (100%) rename parserstate.cpp => src/parserstate.cpp (100%) rename regex.cpp => src/regex.cpp (100%) rename regex.h => src/regex.h (100%) rename scalar.cpp => src/scalar.cpp (100%) rename scalar.h => src/scalar.h (100%) rename scanner.cpp => src/scanner.cpp (100%) rename scanner.h => src/scanner.h (100%) rename scanscalar.cpp => src/scanscalar.cpp (100%) rename scanscalar.h => src/scanscalar.h (100%) rename scantoken.cpp => src/scantoken.cpp (100%) rename sequence.cpp => src/sequence.cpp (100%) rename sequence.h => src/sequence.h (100%) rename simplekey.cpp => src/simplekey.cpp (100%) rename stream.cpp => src/stream.cpp (100%) rename stream.h => src/stream.h (100%) rename tests.cpp => src/tests.cpp (100%) rename tests.h => src/tests.h (100%) rename token.h => src/token.h (100%) create mode 100644 tests/out.yaml diff --git a/exceptions.h b/include/exceptions.h similarity index 100% rename from exceptions.h rename to include/exceptions.h diff --git a/ltnode.h b/include/ltnode.h similarity index 100% rename from ltnode.h rename to include/ltnode.h diff --git a/node.h b/include/node.h similarity index 100% rename from node.h rename to include/node.h diff --git a/parser.h b/include/parser.h similarity index 100% rename from parser.h rename to include/parser.h diff --git a/parserstate.h b/include/parserstate.h similarity index 100% rename from parserstate.h rename to include/parserstate.h diff --git a/content.cpp b/src/content.cpp similarity index 100% rename from content.cpp rename to src/content.cpp diff --git a/content.h b/src/content.h similarity index 100% rename from content.h rename to src/content.h diff --git a/exp.cpp b/src/exp.cpp similarity index 100% rename from exp.cpp rename to src/exp.cpp diff --git a/exp.h b/src/exp.h similarity index 100% rename from exp.h rename to src/exp.h diff --git a/iterator.cpp b/src/iterator.cpp similarity index 100% rename from iterator.cpp rename to src/iterator.cpp diff --git a/main.cpp b/src/main.cpp similarity index 100% rename from main.cpp rename to src/main.cpp diff --git a/map.cpp b/src/map.cpp similarity index 100% rename from map.cpp rename to src/map.cpp diff --git a/map.h b/src/map.h similarity index 100% rename from map.h rename to src/map.h diff --git a/node.cpp b/src/node.cpp similarity index 100% rename from node.cpp rename to src/node.cpp diff --git a/parser.cpp b/src/parser.cpp similarity index 100% rename from parser.cpp rename to src/parser.cpp diff --git a/parserstate.cpp b/src/parserstate.cpp similarity index 100% rename from parserstate.cpp rename to src/parserstate.cpp diff --git a/regex.cpp b/src/regex.cpp similarity index 100% rename from regex.cpp rename to src/regex.cpp diff --git a/regex.h b/src/regex.h similarity index 100% rename from regex.h rename to src/regex.h diff --git a/scalar.cpp b/src/scalar.cpp similarity index 100% rename from scalar.cpp rename to src/scalar.cpp diff --git a/scalar.h b/src/scalar.h similarity index 100% rename from scalar.h rename to src/scalar.h diff --git a/scanner.cpp b/src/scanner.cpp similarity index 100% rename from scanner.cpp rename to src/scanner.cpp diff --git a/scanner.h b/src/scanner.h similarity index 100% rename from scanner.h rename to src/scanner.h diff --git a/scanscalar.cpp b/src/scanscalar.cpp similarity index 100% rename from scanscalar.cpp rename to src/scanscalar.cpp diff --git a/scanscalar.h b/src/scanscalar.h similarity index 100% rename from scanscalar.h rename to src/scanscalar.h diff --git a/scantoken.cpp b/src/scantoken.cpp similarity index 100% rename from scantoken.cpp rename to src/scantoken.cpp diff --git a/sequence.cpp b/src/sequence.cpp similarity index 100% rename from sequence.cpp rename to src/sequence.cpp diff --git a/sequence.h b/src/sequence.h similarity index 100% rename from sequence.h rename to src/sequence.h diff --git a/simplekey.cpp b/src/simplekey.cpp similarity index 100% rename from simplekey.cpp rename to src/simplekey.cpp diff --git a/stream.cpp b/src/stream.cpp similarity index 100% rename from stream.cpp rename to src/stream.cpp diff --git a/stream.h b/src/stream.h similarity index 100% rename from stream.h rename to src/stream.h diff --git a/tests.cpp b/src/tests.cpp similarity index 100% rename from tests.cpp rename to src/tests.cpp diff --git a/tests.h b/src/tests.h similarity index 100% rename from tests.h rename to src/tests.h diff --git a/token.h b/src/token.h similarity index 100% rename from token.h rename to src/token.h diff --git a/tests/out.yaml b/tests/out.yaml new file mode 100644 index 0000000..75b1228 --- /dev/null +++ b/tests/out.yaml @@ -0,0 +1,8 @@ +--- +- "basic node" +- ! "yeah baby" + +--- +- "basic node" +- !> "yeah baby" + diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index b708279..6ef5a5e 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -40,6 +40,7 @@ @@ -205,11 +207,11 @@ Name="Parser" > @@ -217,27 +219,27 @@ Name="Representation" > @@ -248,38 +250,38 @@ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > @@ -287,11 +289,11 @@ Name="Parser" > @@ -299,27 +301,27 @@ Name="Representation" > From 4c1c0977ab3c181689d41bb1c93f20c914e69375 Mon Sep 17 00:00:00 2001 From: beder Date: Mon, 14 Jul 2008 04:37:58 +0000 Subject: [PATCH 052/295] --- src/parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser.cpp b/src/parser.cpp index 0f79d4f..2caaa89 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -30,7 +30,7 @@ namespace YAML // GetNextDocument // . Reads the next document in the queue (of tokens). - // . Throws (ParserException|ParserException)s on errors. + // . Throws a ParserException on error. void Parser::GetNextDocument(Node& document) { // clear node From ef8e9415f8c913ca34dd9618ceec6c6ba5f9eaad Mon Sep 17 00:00:00 2001 From: beder Date: Mon, 14 Jul 2008 04:51:47 +0000 Subject: [PATCH 053/295] Renamed the solution yamlcpp. --- yaml-reader.sln => yamlcpp.sln | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename yaml-reader.sln => yamlcpp.sln (100%) diff --git a/yaml-reader.sln b/yamlcpp.sln similarity index 100% rename from yaml-reader.sln rename to yamlcpp.sln From 11eb40e636d6f02b44ab00ac005824a4d703a9e7 Mon Sep 17 00:00:00 2001 From: beder Date: Mon, 14 Jul 2008 05:03:38 +0000 Subject: [PATCH 054/295] Added a static library project 'yamlcpp' to the solution. --- yamlcpp.sln | 6 + yamlcpp.vcproj | 313 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 319 insertions(+) create mode 100644 yamlcpp.vcproj diff --git a/yamlcpp.sln b/yamlcpp.sln index 1fe1807..e582333 100644 --- a/yamlcpp.sln +++ b/yamlcpp.sln @@ -3,6 +3,8 @@ Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml-reader", "yaml-reader.vcproj", "{E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yamlcpp", "yamlcpp.vcproj", "{3104AB4E-CD31-4F47-95E9-0E8D9374E15D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -13,6 +15,10 @@ Global {E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}.Debug|Win32.Build.0 = Debug|Win32 {E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}.Release|Win32.ActiveCfg = Release|Win32 {E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}.Release|Win32.Build.0 = Release|Win32 + {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Debug|Win32.ActiveCfg = Debug|Win32 + {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Debug|Win32.Build.0 = Debug|Win32 + {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Release|Win32.ActiveCfg = Release|Win32 + {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/yamlcpp.vcproj b/yamlcpp.vcproj new file mode 100644 index 0000000..7bf8f63 --- /dev/null +++ b/yamlcpp.vcproj @@ -0,0 +1,313 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 2ffc7dc6ac9efedf3ff7a54ecaeda7471990a28b Mon Sep 17 00:00:00 2001 From: beder Date: Mon, 14 Jul 2008 05:08:46 +0000 Subject: [PATCH 055/295] Set the yaml-reader project to link to the yamlcpp library. --- src/main.cpp | 6 ++ yaml-reader.vcproj | 146 +-------------------------------------------- 2 files changed, 8 insertions(+), 144 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 6588557..2da42f0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,6 +3,12 @@ #include #include +#ifdef _DEBUG +#pragma comment(lib, "yamlcppd.lib") +#else +#pragma comment(lib, "yamlcpp.lib") +#endif + struct Vec3 { float x, y, z; diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index 6ef5a5e..2d7df5f 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -58,6 +58,7 @@ /> @@ -127,6 +128,7 @@ /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Date: Mon, 14 Jul 2008 05:18:25 +0000 Subject: [PATCH 056/295] Moved the testing source to the yaml-reader folder. --- src/tests.cpp | 81 ----------------------------------- src/tests.h | 10 ----- tests/directives.yaml | 5 --- tests/mixed.yaml | 32 -------------- tests/out.yaml | 8 ---- tests/scalars.yaml | 35 --------------- tests/simple.yaml | 13 ------ yaml-reader.vcproj | 16 +++---- {src => yaml-reader}/main.cpp | 0 yamlcpp.sln | 3 ++ yamlcpp.vcproj | 2 + 11 files changed, 13 insertions(+), 192 deletions(-) delete mode 100644 src/tests.cpp delete mode 100644 src/tests.h delete mode 100644 tests/directives.yaml delete mode 100644 tests/mixed.yaml delete mode 100644 tests/out.yaml delete mode 100644 tests/scalars.yaml delete mode 100644 tests/simple.yaml rename {src => yaml-reader}/main.cpp (100%) diff --git a/src/tests.cpp b/src/tests.cpp deleted file mode 100644 index ad41f67..0000000 --- a/src/tests.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "tests.h" -#include "parser.h" -#include -#include -#include -#include - -namespace YAML -{ - namespace Test - { - // runs all the tests on all data we have - void RunAll() - { - std::vector files; - files.push_back("tests/simple.yaml"); - files.push_back("tests/mixed.yaml"); - files.push_back("tests/scalars.yaml"); - files.push_back("tests/directives.yaml"); - - bool passed = true; - for(unsigned i=0;i - -namespace YAML -{ - namespace Test { - void RunAll(); - - bool Inout(const std::string& file); - } -} \ No newline at end of file diff --git a/tests/directives.yaml b/tests/directives.yaml deleted file mode 100644 index ff09846..0000000 --- a/tests/directives.yaml +++ /dev/null @@ -1,5 +0,0 @@ -%YAML 1.2 -%TAG ! !howdy ---- -- basic node -- ! yeah baby \ No newline at end of file diff --git a/tests/mixed.yaml b/tests/mixed.yaml deleted file mode 100644 index 88da1e7..0000000 --- a/tests/mixed.yaml +++ /dev/null @@ -1,32 +0,0 @@ -- the main thing is a sequence -- here's a key: value - and another: value -- let's inline: [1, 2, 3] - and an inline map: {key: value, 243: 101} -- and multiple indents: - - here's - - a - - list - and another: - - list - - of - - things -- maybe now: - let's: get - pretty: - deep: here - in: - the: nesting - just: to - confuse: - the: heck - out: - - of - - the: parser - if: - - we - - can - - do: that - what: do - you: think? - \ No newline at end of file diff --git a/tests/out.yaml b/tests/out.yaml deleted file mode 100644 index 75b1228..0000000 --- a/tests/out.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -- "basic node" -- ! "yeah baby" - ---- -- "basic node" -- !> "yeah baby" - diff --git a/tests/scalars.yaml b/tests/scalars.yaml deleted file mode 100644 index ae0059a..0000000 --- a/tests/scalars.yaml +++ /dev/null @@ -1,35 +0,0 @@ -- normal scalar, but - over several lines -- | - literal scalar - so we can draw ASCII: - - - - - | - | - ------ -- > - and a folded scalar... so we - can just keep writing various - things. And if we want to keep indentation: - - we just indent a little - see, this stays indented -- >- - Here's a folded scalar - that gets chomped. -- |- - And here's a literal scalar - that gets chomped. -- >2 - Here's a folded scalar - that starts with some indentation. -- ::vector -- ": - ()" -- Up, up, and away! -- -123 -- http://example.com/foo#bar -# Inside flow collection: -- [ ::vector, - ": - ()", - "Up, up and away!", - -123, - http://example.com/foo#bar ] \ No newline at end of file diff --git a/tests/simple.yaml b/tests/simple.yaml deleted file mode 100644 index 55b2d21..0000000 --- a/tests/simple.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -just a scalar ---- -and another scalar ---- -now an end document -... ---- -and now two -... -... ---- -and that's it \ No newline at end of file diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index 2d7df5f..d5d72e5 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -166,11 +166,11 @@ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > @@ -180,7 +180,7 @@ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > @@ -190,23 +190,23 @@ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" > diff --git a/src/main.cpp b/yaml-reader/main.cpp similarity index 100% rename from src/main.cpp rename to yaml-reader/main.cpp diff --git a/yamlcpp.sln b/yamlcpp.sln index e582333..6a0f57f 100644 --- a/yamlcpp.sln +++ b/yamlcpp.sln @@ -2,6 +2,9 @@ Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml-reader", "yaml-reader.vcproj", "{E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}" + ProjectSection(ProjectDependencies) = postProject + {3104AB4E-CD31-4F47-95E9-0E8D9374E15D} = {3104AB4E-CD31-4F47-95E9-0E8D9374E15D} + EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yamlcpp", "yamlcpp.vcproj", "{3104AB4E-CD31-4F47-95E9-0E8D9374E15D}" EndProject diff --git a/yamlcpp.vcproj b/yamlcpp.vcproj index 7bf8f63..2c9ed53 100644 --- a/yamlcpp.vcproj +++ b/yamlcpp.vcproj @@ -41,6 +41,7 @@ Date: Sun, 20 Jul 2008 05:02:01 +0000 Subject: [PATCH 057/295] Replaced the queue of Token pointers with values. We were getting memory leaks (as told by the CRT detectors, which I also added), and there's really no reason (as long as we're careful) to use pointers there. --- include/crt.h | 10 +++++ include/exceptions.h | 2 + include/yaml.h | 6 +++ src/content.cpp | 1 + src/exp.cpp | 1 + src/iterator.cpp | 1 + src/map.cpp | 53 +++++++++++++------------- src/node.cpp | 46 +++++++++++----------- src/parser.cpp | 30 ++++++++------- src/parserstate.cpp | 1 + src/regex.cpp | 1 + src/scalar.cpp | 7 ++-- src/scanner.cpp | 81 ++++++++++++++++----------------------- src/scanner.h | 12 +++--- src/scanscalar.cpp | 1 + src/scantoken.cpp | 57 ++++++++++++++-------------- src/sequence.cpp | 46 +++++++++++----------- src/simplekey.cpp | 5 ++- src/stream.cpp | 1 + test.yaml | 3 -- yaml-reader.vcproj | 2 +- yaml-reader/main.cpp | 88 ++++++++----------------------------------- yaml-reader/tests.cpp | 79 ++++++++++++++++++++++++++++++++++++++ yaml-reader/tests.h | 6 +++ yamlcpp.vcproj | 8 ++++ 25 files changed, 297 insertions(+), 251 deletions(-) create mode 100644 include/crt.h create mode 100644 include/yaml.h delete mode 100644 test.yaml create mode 100644 yaml-reader/tests.cpp create mode 100644 yaml-reader/tests.h diff --git a/include/crt.h b/include/crt.h new file mode 100644 index 0000000..e59a20c --- /dev/null +++ b/include/crt.h @@ -0,0 +1,10 @@ +#pragma once + +// for memory leaks +#ifdef _DEBUG + +#define _CRTDBG_MAP_ALLOC +#include +#include + +#endif // _DEBUG \ No newline at end of file diff --git a/include/exceptions.h b/include/exceptions.h index f3a27f0..0e6031e 100644 --- a/include/exceptions.h +++ b/include/exceptions.h @@ -1,6 +1,7 @@ #pragma once #include +#include namespace YAML { @@ -9,6 +10,7 @@ namespace YAML public: ParserException(int line_, int column_, const std::string& msg_) : line(line_), column(column_), msg(msg_) {} + int line, column; std::string msg; }; diff --git a/include/yaml.h b/include/yaml.h new file mode 100644 index 0000000..08f79ca --- /dev/null +++ b/include/yaml.h @@ -0,0 +1,6 @@ +#pragma once + +#include "crt.h" +#include "parser.h" +#include "node.h" +#include "exceptions.h" \ No newline at end of file diff --git a/src/content.cpp b/src/content.cpp index b68bb25..4995729 100644 --- a/src/content.cpp +++ b/src/content.cpp @@ -1,3 +1,4 @@ +#include "crt.h" #include "content.h" namespace YAML diff --git a/src/exp.cpp b/src/exp.cpp index 05b1b24..8ce2af7 100644 --- a/src/exp.cpp +++ b/src/exp.cpp @@ -1,3 +1,4 @@ +#include "crt.h" #include "exp.h" #include "exceptions.h" #include diff --git a/src/iterator.cpp b/src/iterator.cpp index bd671be..b39cec3 100644 --- a/src/iterator.cpp +++ b/src/iterator.cpp @@ -1,3 +1,4 @@ +#include "crt.h" #include "node.h" #include "exceptions.h" diff --git a/src/map.cpp b/src/map.cpp index 19a3cb9..cdb5fdf 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1,3 +1,4 @@ +#include "crt.h" #include "map.h" #include "node.h" #include "scanner.h" @@ -41,9 +42,9 @@ namespace YAML Clear(); // split based on start token - Token *pToken = pScanner->PeekNextToken(); + Token& token = pScanner->PeekToken(); - switch(pToken->type) { + switch(token.type) { case TT_BLOCK_MAP_START: ParseBlock(pScanner, state); break; case TT_FLOW_MAP_START: ParseFlow(pScanner, state); break; } @@ -52,18 +53,18 @@ namespace YAML void Map::ParseBlock(Scanner *pScanner, const ParserState& state) { // eat start token - pScanner->EatNextToken(); + pScanner->PopToken(); while(1) { - Token *pToken = pScanner->PeekNextToken(); - if(!pToken) + if(pScanner->IsEmpty()) throw ParserException(-1, -1, ErrorMsg::END_OF_MAP); - if(pToken->type != TT_KEY && pToken->type != TT_BLOCK_END) - throw ParserException(pToken->line, pToken->column, ErrorMsg::END_OF_MAP); + Token token = pScanner->PeekToken(); + if(token.type != TT_KEY && token.type != TT_BLOCK_END) + throw ParserException(token.line, token.column, ErrorMsg::END_OF_MAP); - pScanner->PopNextToken(); - if(pToken->type == TT_BLOCK_END) + pScanner->PopToken(); + if(token.type == TT_BLOCK_END) break; Node *pKey = new Node; @@ -74,8 +75,8 @@ namespace YAML pKey->Parse(pScanner, state); // now grab value (optional) - if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { - pScanner->PopNextToken(); + if(!pScanner->IsEmpty() && pScanner->PeekToken().type == TT_VALUE) { + pScanner->PopToken(); pValue->Parse(pScanner, state); } @@ -91,24 +92,24 @@ namespace YAML void Map::ParseFlow(Scanner *pScanner, const ParserState& state) { // eat start token - pScanner->EatNextToken(); + pScanner->PopToken(); while(1) { - Token *pToken = pScanner->PeekNextToken(); - if(!pToken) + if(pScanner->IsEmpty()) throw ParserException(-1, -1, ErrorMsg::END_OF_MAP_FLOW); + Token& token = pScanner->PeekToken(); // first check for end - if(pToken->type == TT_FLOW_MAP_END) { - pScanner->EatNextToken(); + if(token.type == TT_FLOW_MAP_END) { + pScanner->PopToken(); break; } // now it better be a key - if(pToken->type != TT_KEY) - throw ParserException(pToken->line, pToken->column, ErrorMsg::END_OF_MAP_FLOW); + if(token.type != TT_KEY) + throw ParserException(token.line, token.column, ErrorMsg::END_OF_MAP_FLOW); - pScanner->PopNextToken(); + pScanner->PopToken(); Node *pKey = new Node; Node *pValue = new Node; @@ -118,17 +119,17 @@ namespace YAML pKey->Parse(pScanner, state); // now grab value (optional) - if(pScanner->PeekNextToken() && pScanner->PeekNextToken()->type == TT_VALUE) { - pScanner->PopNextToken(); + if(!pScanner->IsEmpty() && pScanner->PeekToken().type == TT_VALUE) { + pScanner->PopToken(); 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) - pToken = pScanner->PeekNextToken(); - if(pToken->type == TT_FLOW_ENTRY) - pScanner->EatNextToken(); - else if(pToken->type != TT_FLOW_MAP_END) - throw ParserException(pToken->line, pToken->column, ErrorMsg::END_OF_MAP_FLOW); + Token& nextToken = pScanner->PeekToken(); + if(nextToken.type == TT_FLOW_ENTRY) + pScanner->PopToken(); + else if(nextToken.type != TT_FLOW_MAP_END) + throw ParserException(nextToken.line, nextToken.column, ErrorMsg::END_OF_MAP_FLOW); m_data[pKey] = pValue; } catch(Exception& e) { diff --git a/src/node.cpp b/src/node.cpp index c878e9a..1250aa0 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -1,3 +1,4 @@ +#include "crt.h" #include "node.h" #include "token.h" #include "scanner.h" @@ -42,11 +43,7 @@ namespace YAML return; // now split based on what kind of node we should be - Token *pToken = pScanner->PeekNextToken(); - if(pToken->type == TT_DOC_END) - return; - - switch(pToken->type) { + switch(pScanner->PeekToken().type) { case TT_SCALAR: m_pContent = new Scalar; m_pContent->Parse(pScanner, state); @@ -61,6 +58,7 @@ namespace YAML case TT_BLOCK_MAP_START: m_pContent = new Map; m_pContent->Parse(pScanner, state); + break; } } @@ -69,53 +67,53 @@ namespace YAML void Node::ParseHeader(Scanner *pScanner, const ParserState& state) { while(1) { - Token *pToken = pScanner->PeekNextToken(); - if(!pToken || (pToken->type != TT_TAG && pToken->type != TT_ANCHOR && pToken->type != TT_ALIAS)) - break; + if(pScanner->IsEmpty()) + return; - switch(pToken->type) { + switch(pScanner->PeekToken().type) { case TT_TAG: ParseTag(pScanner, state); break; case TT_ANCHOR: ParseAnchor(pScanner, state); break; case TT_ALIAS: ParseAlias(pScanner, state); break; + default: return; } } } void Node::ParseTag(Scanner *pScanner, const ParserState& state) { - Token *pToken = pScanner->PeekNextToken(); + Token& token = pScanner->PeekToken(); if(m_tag != "") - throw ParserException(pToken->line, pToken->column, ErrorMsg::MULTIPLE_TAGS); + throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_TAGS); - m_tag = state.TranslateTag(pToken->value); + m_tag = state.TranslateTag(token.value); - for(unsigned i=0;iparams.size();i++) - m_tag += pToken->params[i]; - pScanner->PopNextToken(); + for(unsigned i=0;iPopToken(); } void Node::ParseAnchor(Scanner *pScanner, const ParserState& state) { - Token *pToken = pScanner->PeekNextToken(); + Token& token = pScanner->PeekToken(); if(m_anchor != "") - throw ParserException(pToken->line, pToken->column, ErrorMsg::MULTIPLE_ANCHORS); + throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ANCHORS); - m_anchor = pToken->value; + m_anchor = token.value; m_alias = false; - pScanner->PopNextToken(); + pScanner->PopToken(); } void Node::ParseAlias(Scanner *pScanner, const ParserState& state) { - Token *pToken = pScanner->PeekNextToken(); + Token& token = pScanner->PeekToken(); if(m_anchor != "") - throw ParserException(pToken->line, pToken->column, ErrorMsg::MULTIPLE_ALIASES); + throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ALIASES); if(m_tag != "") - throw ParserException(pToken->line, pToken->column, ErrorMsg::ALIAS_CONTENT); + throw ParserException(token.line, token.column, ErrorMsg::ALIAS_CONTENT); - m_anchor = pToken->value; + m_anchor = token.value; m_alias = true; - pScanner->PopNextToken(); + pScanner->PopToken(); } void Node::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const diff --git a/src/parser.cpp b/src/parser.cpp index 2caaa89..9c40430 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,3 +1,4 @@ +#include "crt.h" #include "parser.h" #include "scanner.h" #include "token.h" @@ -18,7 +19,7 @@ namespace YAML Parser::operator bool() const { - return m_pScanner->PeekNextToken() != 0; + return !m_pScanner->IsEmpty(); } void Parser::Load(std::istream& in) @@ -40,19 +41,19 @@ namespace YAML ParseDirectives(); // we better have some tokens in the queue - if(!m_pScanner->PeekNextToken()) + if(m_pScanner->IsEmpty()) return; // first eat doc start (optional) - if(m_pScanner->PeekNextToken()->type == TT_DOC_START) - m_pScanner->EatNextToken(); + if(m_pScanner->PeekToken().type == TT_DOC_START) + m_pScanner->PopToken(); // now parse our root node document.Parse(m_pScanner, m_state); // and finally eat any doc ends we see - while(m_pScanner->PeekNextToken() && m_pScanner->PeekNextToken()->type == TT_DOC_END) - m_pScanner->EatNextToken(); + while(!m_pScanner->IsEmpty() && m_pScanner->PeekToken().type == TT_DOC_END) + m_pScanner->PopToken(); } // ParseDirectives @@ -62,8 +63,11 @@ namespace YAML bool readDirective = false; while(1) { - Token *pToken = m_pScanner->PeekNextToken(); - if(!pToken || pToken->type != TT_DIRECTIVE) + if(m_pScanner->IsEmpty()) + break; + + Token& token = m_pScanner->PeekToken(); + if(token.type != TT_DIRECTIVE) break; // we keep the directives from the last document if none are specified; @@ -72,8 +76,8 @@ namespace YAML m_state.Reset(); readDirective = true; - HandleDirective(pToken); - m_pScanner->PopNextToken(); + HandleDirective(&token); + m_pScanner->PopToken(); } } @@ -119,11 +123,11 @@ namespace YAML void Parser::PrintTokens(std::ostream& out) { while(1) { - Token *pToken = m_pScanner->GetNextToken(); - if(!pToken) + if(m_pScanner->IsEmpty()) break; - out << *pToken << std::endl; + out << m_pScanner->PeekToken() << std::endl; + m_pScanner->PopToken(); } } } diff --git a/src/parserstate.cpp b/src/parserstate.cpp index d99b970..4a14b3a 100644 --- a/src/parserstate.cpp +++ b/src/parserstate.cpp @@ -1,3 +1,4 @@ +#include "crt.h" #include "parserstate.h" namespace YAML diff --git a/src/regex.cpp b/src/regex.cpp index e7f93e1..cbd1eb0 100644 --- a/src/regex.cpp +++ b/src/regex.cpp @@ -1,3 +1,4 @@ +#include "crt.h" #include "regex.h" namespace YAML diff --git a/src/scalar.cpp b/src/scalar.cpp index 6be1bf4..0038cc1 100644 --- a/src/scalar.cpp +++ b/src/scalar.cpp @@ -1,3 +1,4 @@ +#include "crt.h" #include "scalar.h" #include "scanner.h" #include "token.h" @@ -16,9 +17,9 @@ namespace YAML void Scalar::Parse(Scanner *pScanner, const ParserState& state) { - Token *pToken = pScanner->GetNextToken(); - m_data = pToken->value; - delete pToken; + Token& token = pScanner->PeekToken(); + m_data = token.value; + pScanner->PopToken(); } void Scalar::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) diff --git a/src/scanner.cpp b/src/scanner.cpp index 110d1a3..bf2a23e 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -1,3 +1,4 @@ +#include "crt.h" #include "scanner.h" #include "token.h" #include "exceptions.h" @@ -12,62 +13,46 @@ namespace YAML Scanner::~Scanner() { - while(!m_tokens.empty()) { - delete m_tokens.front(); - m_tokens.pop(); - } } - // GetNextToken - // . Removes and returns the next token on the queue. - Token *Scanner::GetNextToken() + // IsEmpty + // . Returns true if there are no more tokens to be read + bool Scanner::IsEmpty() { - Token *pToken = PeekNextToken(); + PeekToken(); // to ensure that there are tokens in the queue, if possible + return m_tokens.empty(); + } + + // PopToken + // . Simply removes the next token on the queue. + void Scanner::PopToken() + { + PeekToken(); // to ensure that there are tokens in the queue if(!m_tokens.empty()) m_tokens.pop(); - return pToken; } - // PopNextToken - // . Simply removes the next token on the queue. - void Scanner::PopNextToken() - { - GetNextToken(); - } - - // EatNextToken - // . Removes and deletes the next token on the queue - void Scanner::EatNextToken() - { - delete GetNextToken(); - } - - // PeekNextToken + // PeekToken // . Returns (but does not remove) the next token on the queue, and scans if only we need to. - Token *Scanner::PeekNextToken() + Token& Scanner::PeekToken() { while(1) { - Token *pToken = 0; + if(!m_tokens.empty()) { + Token& token = m_tokens.front(); - // is there a token in the queue? - if(!m_tokens.empty()) - pToken = m_tokens.front(); + // return this guy if it's valid + if(token.status == TS_VALID) + return token; - // (here's where we clean up the impossible tokens) - if(pToken && pToken->status == TS_INVALID) { - m_tokens.pop(); - delete pToken; - continue; + // here's where we clean up the impossible tokens + if(token.status == TS_INVALID) { + m_tokens.pop(); + continue; + } + + // note: what's left are the unverified tokens } - // on unverified tokens, we just have to wait - if(pToken && pToken->status == TS_UNVERIFIED) - pToken = 0; - - // then that's what we want - if(pToken) - return pToken; - // no token? maybe we've actually finished if(m_endedStream) break; @@ -76,7 +61,7 @@ namespace YAML ScanNextToken(); } - return 0; + // TODO: find something to return here, or assert (but can't do that! maybe split into two functions?) } // ScanNextToken @@ -254,14 +239,12 @@ namespace YAML // now push m_indents.push(column); - Token *pToken = 0; if(sequence) - pToken = new Token(TT_BLOCK_SEQ_START, INPUT.line, INPUT.column); + m_tokens.push(Token(TT_BLOCK_SEQ_START, INPUT.line, INPUT.column)); else - pToken = new Token(TT_BLOCK_MAP_START, INPUT.line, INPUT.column); + m_tokens.push(Token(TT_BLOCK_MAP_START, INPUT.line, INPUT.column)); - m_tokens.push(pToken); - return pToken; + return &m_tokens.back(); } // PopIndentTo @@ -276,7 +259,7 @@ namespace YAML // now pop away while(!m_indents.empty() && m_indents.top() > column) { m_indents.pop(); - m_tokens.push(new Token(TT_BLOCK_END, INPUT.line, INPUT.column)); + m_tokens.push(Token(TT_BLOCK_END, INPUT.line, INPUT.column)); } } } diff --git a/src/scanner.h b/src/scanner.h index 63a911b..06fd509 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -6,21 +6,19 @@ #include #include #include "stream.h" +#include "token.h" namespace YAML { - struct Token; - class Scanner { public: Scanner(std::istream& in); ~Scanner(); - Token *GetNextToken(); - void EatNextToken(); - void PopNextToken(); - Token *PeekNextToken(); + bool IsEmpty(); + void PopToken(); + Token& PeekToken(); private: // scanning @@ -72,7 +70,7 @@ namespace YAML Stream INPUT; // the output (tokens) - std::queue m_tokens; + std::queue m_tokens; // state info bool m_startedStream, m_endedStream; diff --git a/src/scanscalar.cpp b/src/scanscalar.cpp index c2cf2b9..70abef4 100644 --- a/src/scanscalar.cpp +++ b/src/scanscalar.cpp @@ -1,3 +1,4 @@ +#include "crt.h" #include "scanscalar.h" #include "scanner.h" #include "exp.h" diff --git a/src/scantoken.cpp b/src/scantoken.cpp index 5704a0a..31489ae 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -1,3 +1,4 @@ +#include "crt.h" #include "scanner.h" #include "token.h" #include "exceptions.h" @@ -49,10 +50,10 @@ namespace YAML params.push_back(param); } - Token *pToken = new Token(TT_DIRECTIVE, line, column); - pToken->value = name; - pToken->params = params; - m_tokens.push(pToken); + Token token(TT_DIRECTIVE, line, column); + token.value = name; + token.params = params; + m_tokens.push(token); } // DocStart @@ -65,7 +66,7 @@ namespace YAML // eat int line = INPUT.line, column = INPUT.column; INPUT.eat(3); - m_tokens.push(new Token(TT_DOC_START, line, column)); + m_tokens.push(Token(TT_DOC_START, line, column)); } // DocEnd @@ -78,7 +79,7 @@ namespace YAML // eat int line = INPUT.line, column = INPUT.column; INPUT.eat(3); - m_tokens.push(new Token(TT_DOC_END, line, column)); + m_tokens.push(Token(TT_DOC_END, line, column)); } // FlowStart @@ -93,7 +94,7 @@ namespace YAML int line = INPUT.line, column = INPUT.column; char ch = INPUT.get(); TOKEN_TYPE type = (ch == Keys::FlowSeqStart ? TT_FLOW_SEQ_START : TT_FLOW_MAP_START); - m_tokens.push(new Token(type, line, column)); + m_tokens.push(Token(type, line, column)); } // FlowEnd @@ -109,7 +110,7 @@ namespace YAML int line = INPUT.line, column = INPUT.column; char ch = INPUT.get(); TOKEN_TYPE type = (ch == Keys::FlowSeqEnd ? TT_FLOW_SEQ_END : TT_FLOW_MAP_END); - m_tokens.push(new Token(type, line, column)); + m_tokens.push(Token(type, line, column)); } // FlowEntry @@ -120,7 +121,7 @@ namespace YAML // eat int line = INPUT.line, column = INPUT.column; INPUT.eat(1); - m_tokens.push(new Token(TT_FLOW_ENTRY, line, column)); + m_tokens.push(Token(TT_FLOW_ENTRY, line, column)); } // BlockEntry @@ -140,7 +141,7 @@ namespace YAML // eat int line = INPUT.line, column = INPUT.column; INPUT.eat(1); - m_tokens.push(new Token(TT_BLOCK_ENTRY, line, column)); + m_tokens.push(Token(TT_BLOCK_ENTRY, line, column)); } // Key @@ -163,7 +164,7 @@ namespace YAML // eat int line = INPUT.line, column = INPUT.column; INPUT.eat(1); - m_tokens.push(new Token(TT_KEY, line, column)); + m_tokens.push(Token(TT_KEY, line, column)); } // Value @@ -192,7 +193,7 @@ namespace YAML // eat int line = INPUT.line, column = INPUT.column; INPUT.eat(1); - m_tokens.push(new Token(TT_VALUE, line, column)); + m_tokens.push(Token(TT_VALUE, line, column)); } // AnchorOrAlias @@ -224,9 +225,9 @@ namespace YAML throw ParserException(INPUT.line, INPUT.column, alias ? ErrorMsg::CHAR_IN_ALIAS : ErrorMsg::CHAR_IN_ANCHOR); // and we're done - Token *pToken = new Token(alias ? TT_ALIAS : TT_ANCHOR, line, column); - pToken->value = name; - m_tokens.push(pToken); + Token token(alias ? TT_ALIAS : TT_ANCHOR, line, column); + token.value = name; + m_tokens.push(token); } // Tag @@ -261,10 +262,10 @@ namespace YAML handle = "!"; } - Token *pToken = new Token(TT_TAG, line, column); - pToken->value = handle; - pToken->params.push_back(suffix); - m_tokens.push(pToken); + Token token(TT_TAG, line, column); + token.value = handle; + token.params.push_back(suffix); + m_tokens.push(token); } // PlainScalar @@ -298,9 +299,9 @@ namespace YAML //if(Exp::IllegalCharInScalar.Matches(INPUT)) // throw ParserException(INPUT.line, INPUT.column, ErrorMsg::CHAR_IN_SCALAR); - Token *pToken = new Token(TT_SCALAR, line, column); - pToken->value = scalar; - m_tokens.push(pToken); + Token token(TT_SCALAR, line, column); + token.value = scalar; + m_tokens.push(token); } // QuotedScalar @@ -332,9 +333,9 @@ namespace YAML scalar = ScanScalar(INPUT, params); m_simpleKeyAllowed = false; - Token *pToken = new Token(TT_SCALAR, line, column); - pToken->value = scalar; - m_tokens.push(pToken); + Token token(TT_SCALAR, line, column); + token.value = scalar; + m_tokens.push(token); } // BlockScalarToken @@ -397,8 +398,8 @@ namespace YAML // simple keys always ok after block scalars (since we're gonna start a new line anyways) m_simpleKeyAllowed = true; - Token *pToken = new Token(TT_SCALAR, line, column); - pToken->value = scalar; - m_tokens.push(pToken); + Token token(TT_SCALAR, line, column); + token.value = scalar; + m_tokens.push(token); } } diff --git a/src/sequence.cpp b/src/sequence.cpp index 8c1e3ca..fed6a97 100644 --- a/src/sequence.cpp +++ b/src/sequence.cpp @@ -1,3 +1,4 @@ +#include "crt.h" #include "sequence.h" #include "node.h" #include "scanner.h" @@ -51,9 +52,9 @@ namespace YAML Clear(); // split based on start token - Token *pToken = pScanner->PeekNextToken(); + Token& token = pScanner->PeekToken(); - switch(pToken->type) { + switch(token.type) { case TT_BLOCK_SEQ_START: ParseBlock(pScanner, state); break; case TT_BLOCK_ENTRY: ParseImplicit(pScanner, state); break; case TT_FLOW_SEQ_START: ParseFlow(pScanner, state); break; @@ -63,18 +64,18 @@ namespace YAML void Sequence::ParseBlock(Scanner *pScanner, const ParserState& state) { // eat start token - pScanner->EatNextToken(); + pScanner->PopToken(); while(1) { - Token *pToken = pScanner->PeekNextToken(); - if(!pToken) + if(pScanner->IsEmpty()) throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ); - if(pToken->type != TT_BLOCK_ENTRY && pToken->type != TT_BLOCK_END) - throw ParserException(pToken->line, pToken->column, ErrorMsg::END_OF_SEQ); + Token token = pScanner->PeekToken(); + if(token.type != TT_BLOCK_ENTRY && token.type != TT_BLOCK_END) + throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ); - pScanner->PopNextToken(); - if(pToken->type == TT_BLOCK_END) + pScanner->PopToken(); + if(token.type == TT_BLOCK_END) break; Node *pNode = new Node; @@ -86,16 +87,16 @@ namespace YAML void Sequence::ParseImplicit(Scanner *pScanner, const ParserState& state) { while(1) { - Token *pToken = pScanner->PeekNextToken(); // we're actually *allowed* to have no tokens at some point - if(!pToken) + if(pScanner->IsEmpty()) break; // and we end at anything other than a block entry - if(pToken->type != TT_BLOCK_ENTRY) + Token& token = pScanner->PeekToken(); + if(token.type != TT_BLOCK_ENTRY) break; - pScanner->PopNextToken(); + pScanner->PopToken(); Node *pNode = new Node; m_data.push_back(pNode); @@ -106,16 +107,15 @@ namespace YAML void Sequence::ParseFlow(Scanner *pScanner, const ParserState& state) { // eat start token - pScanner->EatNextToken(); + pScanner->PopToken(); while(1) { - Token *pToken = pScanner->PeekNextToken(); - if(!pToken) + if(pScanner->IsEmpty()) throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ_FLOW); // first check for end - if(pToken->type == TT_FLOW_SEQ_END) { - pScanner->PopNextToken(); + if(pScanner->PeekToken().type == TT_FLOW_SEQ_END) { + pScanner->PopToken(); break; } @@ -125,11 +125,11 @@ namespace YAML 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) - pToken = pScanner->PeekNextToken(); - if(pToken->type == TT_FLOW_ENTRY) - pScanner->EatNextToken(); - else if(pToken->type != TT_FLOW_SEQ_END) - throw ParserException(pToken->line, pToken->column, ErrorMsg::END_OF_SEQ_FLOW); + Token& token = pScanner->PeekToken(); + if(token.type == TT_FLOW_ENTRY) + pScanner->PopToken(); + else if(token.type != TT_FLOW_SEQ_END) + throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ_FLOW); } } diff --git a/src/simplekey.cpp b/src/simplekey.cpp index a5e6bc3..e9d25ee 100644 --- a/src/simplekey.cpp +++ b/src/simplekey.cpp @@ -1,3 +1,4 @@ +#include "crt.h" #include "scanner.h" #include "token.h" #include "exceptions.h" @@ -39,9 +40,9 @@ namespace YAML key.pMapStart->status = TS_UNVERIFIED; // then add the (now unverified) key - key.pKey = new Token(TT_KEY, INPUT.line, INPUT.column); + m_tokens.push(Token(TT_KEY, INPUT.line, INPUT.column)); + key.pKey = &m_tokens.back(); key.pKey->status = TS_UNVERIFIED; - m_tokens.push(key.pKey); m_simpleKeys.push(key); } diff --git a/src/stream.cpp b/src/stream.cpp index f3668fe..38f4c8e 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -1,3 +1,4 @@ +#include "crt.h" #include "stream.h" namespace YAML diff --git a/test.yaml b/test.yaml deleted file mode 100644 index 28e1b7d..0000000 --- a/test.yaml +++ /dev/null @@ -1,3 +0,0 @@ -abeginning: value -zend: value -middle: value \ No newline at end of file diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index d5d72e5..b864dc6 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -206,7 +206,7 @@ > diff --git a/yaml-reader/main.cpp b/yaml-reader/main.cpp index 2da42f0..3f47840 100644 --- a/yaml-reader/main.cpp +++ b/yaml-reader/main.cpp @@ -1,4 +1,4 @@ -#include "parser.h" +#include "yaml.h" #include "tests.h" #include #include @@ -9,85 +9,29 @@ #pragma comment(lib, "yamlcpp.lib") #endif -struct Vec3 { - float x, y, z; - - friend std::ostream& operator << (std::ostream& out, const Vec3& v) { - out << v.x << " " << v.y << " " << v.z; - return out; - } -}; - -void operator >> (const YAML::Node& node, Vec3& v) +void run() { - node[0] >> v.x; - node[1] >> v.y; - node[2] >> v.z; -} + std::ifstream fin("yaml-reader/tests/test.yaml"); -struct Room { - std::string name; - Vec3 pos, size; - float height; + try { + YAML::Parser parser(fin); + if(!parser) + return; - friend std::ostream& operator << (std::ostream& out, const Room& room) { - out << "Name: " << room.name << std::endl; - out << "Pos: " << room.pos << std::endl; - out << "Size: " << room.size << std::endl; - out << "Height: " << room.height << std::endl; - return out; - } -}; - -void operator >> (const YAML::Node& node, Room& room) -{ - node["name"] >> room.name; - node["pos"] >> room.pos; - node["size"] >> room.size; - node["height"] >> room.height; -} - -struct Level { - std::vector rooms; - - friend std::ostream& operator << (std::ostream& out, const Level& level) { - for(unsigned i=0;i> (const YAML::Node& node, Level& level) -{ - const YAML::Node& rooms = node["rooms"]; - for(unsigned i=0;i> room; - level.rooms.push_back(room); + YAML::Node doc; + parser.GetNextDocument(doc); + std::cout << doc; + } catch(YAML::Exception&) { + std::cout << "Error parsing the yaml!\n"; } } int main() -{ - YAML::Test::RunAll(); - - //std::ifstream fin("test.yaml"); - - //try { - // YAML::Parser parser(fin); - // if(!parser) - // return 0; - - // YAML::Node doc; - // parser.GetNextDocument(doc); - // std::cout << doc; - //} catch(YAML::Exception&) { - // std::cout << "Error parsing the yaml!\n"; - //} +{ + _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF); + Test::RunAll(); + run(); getchar(); - return 0; } diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp new file mode 100644 index 0000000..48ce8ef --- /dev/null +++ b/yaml-reader/tests.cpp @@ -0,0 +1,79 @@ +#include "yaml.h" +#include "tests.h" +#include "parser.h" +#include +#include +#include +#include + +namespace Test +{ + // runs all the tests on all data we have + void RunAll() + { + std::vector files; + files.push_back("yaml-reader/tests/simple.yaml"); + files.push_back("yaml-reader/tests/mixed.yaml"); + files.push_back("yaml-reader/tests/scalars.yaml"); + files.push_back("yaml-reader/tests/directives.yaml"); + + bool passed = true; + for(unsigned i=0;i + +namespace Test { + void RunAll(); + bool Inout(const std::string& file); +} diff --git a/yamlcpp.vcproj b/yamlcpp.vcproj index 2c9ed53..0bd0e81 100644 --- a/yamlcpp.vcproj +++ b/yamlcpp.vcproj @@ -230,10 +230,18 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + + + From 57255a9898400256f332d8e6b6af878d18c86c7f Mon Sep 17 00:00:00 2001 From: beder Date: Mon, 21 Jul 2008 02:54:39 +0000 Subject: [PATCH 058/295] Switched the Iterator implementation to a dedicated helper class (to hide the specific implementation, since it's pretty messy and may change). --- include/iterator.h | 29 ++++++++++++++ include/node.h | 28 +------------- include/yaml.h | 1 + src/iterator.cpp | 80 +++++++++++++++++++++++---------------- src/iterpriv.cpp | 17 +++++++++ src/iterpriv.h | 23 +++++++++++ {include => src}/ltnode.h | 0 src/node.cpp | 13 ++++--- yaml-reader/main.cpp | 6 ++- yamlcpp.vcproj | 14 ++++++- 10 files changed, 143 insertions(+), 68 deletions(-) create mode 100644 include/iterator.h create mode 100644 src/iterpriv.cpp create mode 100644 src/iterpriv.h rename {include => src}/ltnode.h (100%) diff --git a/include/iterator.h b/include/iterator.h new file mode 100644 index 0000000..b0b7e34 --- /dev/null +++ b/include/iterator.h @@ -0,0 +1,29 @@ +#pragma once + +namespace YAML +{ + class Node; + struct IterPriv; + + class Iterator + { + public: + Iterator(); + Iterator(IterPriv *pData); + Iterator(const Iterator& rhs); + ~Iterator(); + + friend bool operator == (const Iterator& it, const Iterator& jt); + friend bool operator != (const Iterator& it, const Iterator& jt); + Iterator& operator = (const Iterator& rhs); + Iterator& operator ++ (); + Iterator operator ++ (int); + const Node& operator * (); + const Node *operator -> (); + const Node& first(); + const Node& second(); + + private: + IterPriv *m_pData; + }; +} diff --git a/include/node.h b/include/node.h index 9bc88ca..f6a2ef6 100644 --- a/include/node.h +++ b/include/node.h @@ -6,7 +6,7 @@ #include #include "parserstate.h" #include "exceptions.h" -#include "ltnode.h" +#include "iterator.h" namespace YAML { @@ -15,32 +15,6 @@ namespace YAML class Node { - public: - class Iterator - { - public: - Iterator(); - Iterator(std::vector ::const_iterator it); - Iterator(std::map ::const_iterator it); - ~Iterator(); - - friend bool operator == (const Iterator& it, const Iterator& jt); - friend bool operator != (const Iterator& it, const Iterator& jt); - Iterator& operator ++ (); - Iterator operator ++ (int); - const Node& operator * (); - const Node *operator -> (); - const Node& first(); - const Node& second(); - - private: - enum ITER_TYPE { IT_NONE, IT_SEQ, IT_MAP }; - ITER_TYPE type; - - std::vector ::const_iterator seqIter; - std::map ::const_iterator mapIter; - }; - public: Node(); ~Node(); diff --git a/include/yaml.h b/include/yaml.h index 08f79ca..de7f222 100644 --- a/include/yaml.h +++ b/include/yaml.h @@ -3,4 +3,5 @@ #include "crt.h" #include "parser.h" #include "node.h" +#include "iterator.h" #include "exceptions.h" \ No newline at end of file diff --git a/src/iterator.cpp b/src/iterator.cpp index b39cec3..bc3233a 100644 --- a/src/iterator.cpp +++ b/src/iterator.cpp @@ -1,93 +1,107 @@ #include "crt.h" #include "node.h" #include "exceptions.h" +#include "iterpriv.h" namespace YAML { - Node::Iterator::Iterator(): type(IT_NONE) + Iterator::Iterator(): m_pData(0) + { + m_pData = new IterPriv; + } + + Iterator::Iterator(IterPriv *pData): m_pData(pData) { } - Node::Iterator::Iterator(std::vector ::const_iterator it): seqIter(it), type(IT_SEQ) + Iterator::Iterator(const Iterator& rhs): m_pData(0) { + m_pData = new IterPriv(*rhs.m_pData); } - Node::Iterator::Iterator(std::map ::const_iterator it): mapIter(it), type(IT_MAP) + Iterator& Iterator::operator = (const Iterator& rhs) { + if(this == &rhs) + return *this; + + delete m_pData; + m_pData = new IterPriv(*rhs.m_pData); + return *this; } - Node::Iterator::~Iterator() + Iterator::~Iterator() { + delete m_pData; } - Node::Iterator& Node::Iterator::operator ++ () + Iterator& Iterator::operator ++ () { - if(type == IT_SEQ) - ++seqIter; - else if(type == IT_MAP) - ++mapIter; + if(m_pData->type == IterPriv::IT_SEQ) + ++m_pData->seqIter; + else if(m_pData->type == IterPriv::IT_MAP) + ++m_pData->mapIter; return *this; } - Node::Iterator Node::Iterator::operator ++ (int) + Iterator Iterator::operator ++ (int) { Iterator temp = *this; - if(type == IT_SEQ) - ++seqIter; - else if(type == IT_MAP) - ++mapIter; + if(m_pData->type == IterPriv::IT_SEQ) + ++m_pData->seqIter; + else if(m_pData->type == IterPriv::IT_MAP) + ++m_pData->mapIter; return temp; } - const Node& Node::Iterator::operator * () + const Node& Iterator::operator * () { - if(type == IT_SEQ) - return **seqIter; + if(m_pData->type == IterPriv::IT_SEQ) + return **m_pData->seqIter; throw BadDereference(); } - const Node *Node::Iterator::operator -> () + const Node *Iterator::operator -> () { - if(type == IT_SEQ) - return &**seqIter; + if(m_pData->type == IterPriv::IT_SEQ) + return &**m_pData->seqIter; throw BadDereference(); } - const Node& Node::Iterator::first() + const Node& Iterator::first() { - if(type == IT_MAP) - return *mapIter->first; + if(m_pData->type == IterPriv::IT_MAP) + return *m_pData->mapIter->first; throw BadDereference(); } - const Node& Node::Iterator::second() + const Node& Iterator::second() { - if(type == IT_MAP) - return *mapIter->second; + if(m_pData->type == IterPriv::IT_MAP) + return *m_pData->mapIter->second; throw BadDereference(); } - bool operator == (const Node::Iterator& it, const Node::Iterator& jt) + bool operator == (const Iterator& it, const Iterator& jt) { - if(it.type != jt.type) + if(it.m_pData->type != jt.m_pData->type) return false; - if(it.type == Node::Iterator::IT_SEQ) - return it.seqIter == jt.seqIter; - else if(it.type == Node::Iterator::IT_MAP) - return it.mapIter == jt.mapIter; + if(it.m_pData->type == IterPriv::IT_SEQ) + return it.m_pData->seqIter == jt.m_pData->seqIter; + else if(it.m_pData->type == IterPriv::IT_MAP) + return it.m_pData->mapIter == jt.m_pData->mapIter; return true; } - bool operator != (const Node::Iterator& it, const Node::Iterator& jt) + bool operator != (const Iterator& it, const Iterator& jt) { return !(it == jt); } diff --git a/src/iterpriv.cpp b/src/iterpriv.cpp new file mode 100644 index 0000000..e2ff8f2 --- /dev/null +++ b/src/iterpriv.cpp @@ -0,0 +1,17 @@ +#include "crt.h" +#include "iterpriv.h" + +namespace YAML +{ + IterPriv::IterPriv(): type(IT_NONE) + { + } + + IterPriv::IterPriv(std::vector ::const_iterator it): seqIter(it), type(IT_SEQ) + { + } + + IterPriv::IterPriv(std::map ::const_iterator it): mapIter(it), type(IT_MAP) + { + } +} diff --git a/src/iterpriv.h b/src/iterpriv.h new file mode 100644 index 0000000..5946ee9 --- /dev/null +++ b/src/iterpriv.h @@ -0,0 +1,23 @@ +#pragma once + +#include "ltnode.h" +#include +#include + +namespace YAML +{ + class Node; + + struct IterPriv + { + IterPriv(); + IterPriv(std::vector ::const_iterator it); + IterPriv(std::map ::const_iterator it); + + enum ITER_TYPE { IT_NONE, IT_SEQ, IT_MAP }; + ITER_TYPE type; + + std::vector ::const_iterator seqIter; + std::map ::const_iterator mapIter; + }; +} diff --git a/include/ltnode.h b/src/ltnode.h similarity index 100% rename from include/ltnode.h rename to src/ltnode.h diff --git a/src/node.cpp b/src/node.cpp index 1250aa0..c66d001 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -7,6 +7,7 @@ #include "scalar.h" #include "sequence.h" #include "map.h" +#include "iterpriv.h" namespace YAML { @@ -145,36 +146,36 @@ namespace YAML // begin // Returns an iterator to the beginning of this (sequence or map). - Node::Iterator Node::begin() const + Iterator Node::begin() const { if(!m_pContent) return Iterator(); std::vector ::const_iterator seqIter; if(m_pContent->GetBegin(seqIter)) - return Iterator(seqIter); + return Iterator(new IterPriv(seqIter)); std::map ::const_iterator mapIter; if(m_pContent->GetBegin(mapIter)) - return Iterator(mapIter); + return Iterator(new IterPriv(mapIter)); return Iterator(); } // end // . Returns an iterator to the end of this (sequence or map). - Node::Iterator Node::end() const + Iterator Node::end() const { if(!m_pContent) return Iterator(); std::vector ::const_iterator seqIter; if(m_pContent->GetEnd(seqIter)) - return Iterator(seqIter); + return Iterator(new IterPriv(seqIter)); std::map ::const_iterator mapIter; if(m_pContent->GetEnd(mapIter)) - return Iterator(mapIter); + return Iterator(new IterPriv(mapIter)); return Iterator(); } diff --git a/yaml-reader/main.cpp b/yaml-reader/main.cpp index 3f47840..c7ef6ac 100644 --- a/yaml-reader/main.cpp +++ b/yaml-reader/main.cpp @@ -20,7 +20,11 @@ void run() YAML::Node doc; parser.GetNextDocument(doc); - std::cout << doc; + for(YAML::Iterator it=doc.begin();it!=doc.end();++it) { + std::string item; + *it >> item; + std::cout << item << "\n"; + } } catch(YAML::Exception&) { std::cout << "Error parsing the yaml!\n"; } diff --git a/yamlcpp.vcproj b/yamlcpp.vcproj index 0bd0e81..7d82294 100644 --- a/yamlcpp.vcproj +++ b/yamlcpp.vcproj @@ -175,6 +175,10 @@ RelativePath=".\src\iterator.cpp" > + + @@ -262,7 +266,15 @@ > + + + + Date: Wed, 23 Jul 2008 04:38:18 +0000 Subject: [PATCH 059/295] Small changes in the iterator code. Changed the public interface of Scanner to resemble an STL container. --- include/crt.h | 2 +- include/iterator.h | 13 +++++++------ include/parser.h | 5 +++++ src/iterator.cpp | 10 +++++----- src/iterpriv.cpp | 17 ----------------- src/iterpriv.h | 8 +++++--- src/map.cpp | 34 ++++++++++++++++------------------ src/node.cpp | 18 +++++++++--------- src/parser.cpp | 24 ++++++++++++------------ src/scalar.cpp | 4 ++-- src/scanner.cpp | 39 +++++++++++++++++++++++++-------------- src/scanner.h | 12 +++++++----- src/sequence.cpp | 30 ++++++++++++++---------------- yamlcpp.vcproj | 4 ---- 14 files changed, 108 insertions(+), 112 deletions(-) delete mode 100644 src/iterpriv.cpp diff --git a/include/crt.h b/include/crt.h index e59a20c..82f13ec 100644 --- a/include/crt.h +++ b/include/crt.h @@ -1,6 +1,6 @@ #pragma once -// for memory leaks +// for detecting memory leaks #ifdef _DEBUG #define _CRTDBG_MAP_ALLOC diff --git a/include/iterator.h b/include/iterator.h index b0b7e34..afaddb6 100644 --- a/include/iterator.h +++ b/include/iterator.h @@ -13,15 +13,16 @@ namespace YAML Iterator(const Iterator& rhs); ~Iterator(); - friend bool operator == (const Iterator& it, const Iterator& jt); - friend bool operator != (const Iterator& it, const Iterator& jt); Iterator& operator = (const Iterator& rhs); Iterator& operator ++ (); Iterator operator ++ (int); - const Node& operator * (); - const Node *operator -> (); - const Node& first(); - const Node& second(); + const Node& operator * () const; + const Node *operator -> () const; + const Node& first() const; + const Node& second() const; + + friend bool operator == (const Iterator& it, const Iterator& jt); + friend bool operator != (const Iterator& it, const Iterator& jt); private: IterPriv *m_pData; diff --git a/include/parser.h b/include/parser.h index 2b9b8ea..ef4d656 100644 --- a/include/parser.h +++ b/include/parser.h @@ -30,6 +30,11 @@ namespace YAML void HandleYamlDirective(Token *pToken); void HandleTagDirective(Token *pToken); + private: + // can't copy this + Parser(const Parser& rhs) {} + Parser& operator = (const Parser& rhs) { return *this; } + private: Scanner *m_pScanner; ParserState m_state; diff --git a/src/iterator.cpp b/src/iterator.cpp index bc3233a..1ce3dc0 100644 --- a/src/iterator.cpp +++ b/src/iterator.cpp @@ -56,7 +56,7 @@ namespace YAML return temp; } - const Node& Iterator::operator * () + const Node& Iterator::operator * () const { if(m_pData->type == IterPriv::IT_SEQ) return **m_pData->seqIter; @@ -64,15 +64,15 @@ namespace YAML throw BadDereference(); } - const Node *Iterator::operator -> () + const Node *Iterator::operator -> () const { if(m_pData->type == IterPriv::IT_SEQ) - return &**m_pData->seqIter; + return *m_pData->seqIter; throw BadDereference(); } - const Node& Iterator::first() + const Node& Iterator::first() const { if(m_pData->type == IterPriv::IT_MAP) return *m_pData->mapIter->first; @@ -80,7 +80,7 @@ namespace YAML throw BadDereference(); } - const Node& Iterator::second() + const Node& Iterator::second() const { if(m_pData->type == IterPriv::IT_MAP) return *m_pData->mapIter->second; diff --git a/src/iterpriv.cpp b/src/iterpriv.cpp deleted file mode 100644 index e2ff8f2..0000000 --- a/src/iterpriv.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "crt.h" -#include "iterpriv.h" - -namespace YAML -{ - IterPriv::IterPriv(): type(IT_NONE) - { - } - - IterPriv::IterPriv(std::vector ::const_iterator it): seqIter(it), type(IT_SEQ) - { - } - - IterPriv::IterPriv(std::map ::const_iterator it): mapIter(it), type(IT_MAP) - { - } -} diff --git a/src/iterpriv.h b/src/iterpriv.h index 5946ee9..80d7d6a 100644 --- a/src/iterpriv.h +++ b/src/iterpriv.h @@ -8,11 +8,13 @@ namespace YAML { class Node; + // IterPriv + // . The implementation for iterators - essentially a union of sequence and map iterators. struct IterPriv { - IterPriv(); - IterPriv(std::vector ::const_iterator it); - IterPriv(std::map ::const_iterator it); + IterPriv(): type(IT_NONE) {} + IterPriv(std::vector ::const_iterator it): seqIter(it), type(IT_SEQ) {} + IterPriv(std::map ::const_iterator it): mapIter(it), type(IT_MAP) {} enum ITER_TYPE { IT_NONE, IT_SEQ, IT_MAP }; ITER_TYPE type; diff --git a/src/map.cpp b/src/map.cpp index cdb5fdf..bfd8b6f 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -42,9 +42,7 @@ namespace YAML Clear(); // split based on start token - Token& token = pScanner->PeekToken(); - - switch(token.type) { + switch(pScanner->peek().type) { case TT_BLOCK_MAP_START: ParseBlock(pScanner, state); break; case TT_FLOW_MAP_START: ParseFlow(pScanner, state); break; } @@ -53,17 +51,17 @@ namespace YAML void Map::ParseBlock(Scanner *pScanner, const ParserState& state) { // eat start token - pScanner->PopToken(); + pScanner->pop(); while(1) { - if(pScanner->IsEmpty()) + if(pScanner->empty()) throw ParserException(-1, -1, ErrorMsg::END_OF_MAP); - Token token = pScanner->PeekToken(); + Token token = pScanner->peek(); if(token.type != TT_KEY && token.type != TT_BLOCK_END) throw ParserException(token.line, token.column, ErrorMsg::END_OF_MAP); - pScanner->PopToken(); + pScanner->pop(); if(token.type == TT_BLOCK_END) break; @@ -75,8 +73,8 @@ namespace YAML pKey->Parse(pScanner, state); // now grab value (optional) - if(!pScanner->IsEmpty() && pScanner->PeekToken().type == TT_VALUE) { - pScanner->PopToken(); + if(!pScanner->empty() && pScanner->peek().type == TT_VALUE) { + pScanner->pop(); pValue->Parse(pScanner, state); } @@ -92,16 +90,16 @@ namespace YAML void Map::ParseFlow(Scanner *pScanner, const ParserState& state) { // eat start token - pScanner->PopToken(); + pScanner->pop(); while(1) { - if(pScanner->IsEmpty()) + if(pScanner->empty()) throw ParserException(-1, -1, ErrorMsg::END_OF_MAP_FLOW); - Token& token = pScanner->PeekToken(); + Token& token = pScanner->peek(); // first check for end if(token.type == TT_FLOW_MAP_END) { - pScanner->PopToken(); + pScanner->pop(); break; } @@ -109,7 +107,7 @@ namespace YAML if(token.type != TT_KEY) throw ParserException(token.line, token.column, ErrorMsg::END_OF_MAP_FLOW); - pScanner->PopToken(); + pScanner->pop(); Node *pKey = new Node; Node *pValue = new Node; @@ -119,15 +117,15 @@ namespace YAML pKey->Parse(pScanner, state); // now grab value (optional) - if(!pScanner->IsEmpty() && pScanner->PeekToken().type == TT_VALUE) { - pScanner->PopToken(); + if(!pScanner->empty() && pScanner->peek().type == TT_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->PeekToken(); + Token& nextToken = pScanner->peek(); if(nextToken.type == TT_FLOW_ENTRY) - pScanner->PopToken(); + pScanner->pop(); else if(nextToken.type != TT_FLOW_MAP_END) throw ParserException(nextToken.line, nextToken.column, ErrorMsg::END_OF_MAP_FLOW); diff --git a/src/node.cpp b/src/node.cpp index c66d001..f67ab55 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -44,7 +44,7 @@ namespace YAML return; // now split based on what kind of node we should be - switch(pScanner->PeekToken().type) { + switch(pScanner->peek().type) { case TT_SCALAR: m_pContent = new Scalar; m_pContent->Parse(pScanner, state); @@ -68,10 +68,10 @@ namespace YAML void Node::ParseHeader(Scanner *pScanner, const ParserState& state) { while(1) { - if(pScanner->IsEmpty()) + if(pScanner->empty()) return; - switch(pScanner->PeekToken().type) { + switch(pScanner->peek().type) { case TT_TAG: ParseTag(pScanner, state); break; case TT_ANCHOR: ParseAnchor(pScanner, state); break; case TT_ALIAS: ParseAlias(pScanner, state); break; @@ -82,7 +82,7 @@ namespace YAML void Node::ParseTag(Scanner *pScanner, const ParserState& state) { - Token& token = pScanner->PeekToken(); + Token& token = pScanner->peek(); if(m_tag != "") throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_TAGS); @@ -90,23 +90,23 @@ namespace YAML for(unsigned i=0;iPopToken(); + pScanner->pop(); } void Node::ParseAnchor(Scanner *pScanner, const ParserState& state) { - Token& token = pScanner->PeekToken(); + Token& token = pScanner->peek(); if(m_anchor != "") throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ANCHORS); m_anchor = token.value; m_alias = false; - pScanner->PopToken(); + pScanner->pop(); } void Node::ParseAlias(Scanner *pScanner, const ParserState& state) { - Token& token = pScanner->PeekToken(); + Token& token = pScanner->peek(); if(m_anchor != "") throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ALIASES); if(m_tag != "") @@ -114,7 +114,7 @@ namespace YAML m_anchor = token.value; m_alias = true; - pScanner->PopToken(); + pScanner->pop(); } void Node::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const diff --git a/src/parser.cpp b/src/parser.cpp index 9c40430..7d4169d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -19,7 +19,7 @@ namespace YAML Parser::operator bool() const { - return !m_pScanner->IsEmpty(); + return !m_pScanner->empty(); } void Parser::Load(std::istream& in) @@ -41,19 +41,19 @@ namespace YAML ParseDirectives(); // we better have some tokens in the queue - if(m_pScanner->IsEmpty()) + if(m_pScanner->empty()) return; // first eat doc start (optional) - if(m_pScanner->PeekToken().type == TT_DOC_START) - m_pScanner->PopToken(); + if(m_pScanner->peek().type == TT_DOC_START) + m_pScanner->pop(); // now parse our root node document.Parse(m_pScanner, m_state); // and finally eat any doc ends we see - while(!m_pScanner->IsEmpty() && m_pScanner->PeekToken().type == TT_DOC_END) - m_pScanner->PopToken(); + while(!m_pScanner->empty() && m_pScanner->peek().type == TT_DOC_END) + m_pScanner->pop(); } // ParseDirectives @@ -63,10 +63,10 @@ namespace YAML bool readDirective = false; while(1) { - if(m_pScanner->IsEmpty()) + if(m_pScanner->empty()) break; - Token& token = m_pScanner->PeekToken(); + Token& token = m_pScanner->peek(); if(token.type != TT_DIRECTIVE) break; @@ -77,7 +77,7 @@ namespace YAML readDirective = true; HandleDirective(&token); - m_pScanner->PopToken(); + m_pScanner->pop(); } } @@ -123,11 +123,11 @@ namespace YAML void Parser::PrintTokens(std::ostream& out) { while(1) { - if(m_pScanner->IsEmpty()) + if(m_pScanner->empty()) break; - out << m_pScanner->PeekToken() << std::endl; - m_pScanner->PopToken(); + out << m_pScanner->peek() << std::endl; + m_pScanner->pop(); } } } diff --git a/src/scalar.cpp b/src/scalar.cpp index 0038cc1..e560fb8 100644 --- a/src/scalar.cpp +++ b/src/scalar.cpp @@ -17,9 +17,9 @@ namespace YAML void Scalar::Parse(Scanner *pScanner, const ParserState& state) { - Token& token = pScanner->PeekToken(); + Token& token = pScanner->peek(); m_data = token.value; - pScanner->PopToken(); + pScanner->pop(); } void Scalar::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) diff --git a/src/scanner.cpp b/src/scanner.cpp index bf2a23e..b800840 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -3,6 +3,7 @@ #include "token.h" #include "exceptions.h" #include "exp.h" +#include namespace YAML { @@ -15,34 +16,46 @@ namespace YAML { } - // IsEmpty + // empty // . Returns true if there are no more tokens to be read - bool Scanner::IsEmpty() + bool Scanner::empty() { - PeekToken(); // to ensure that there are tokens in the queue, if possible + EnsureTokensInQueue(); return m_tokens.empty(); } - // PopToken + // pop // . Simply removes the next token on the queue. - void Scanner::PopToken() + void Scanner::pop() { - PeekToken(); // to ensure that there are tokens in the queue + EnsureTokensInQueue(); if(!m_tokens.empty()) m_tokens.pop(); } - // PeekToken - // . Returns (but does not remove) the next token on the queue, and scans if only we need to. - Token& Scanner::PeekToken() + // peek + // . Returns (but does not remove) the next token on the queue. + Token& Scanner::peek() + { + EnsureTokensInQueue(); + assert(!m_tokens.empty()); // should we be asserting here? I mean, we really just be checking + // if it's empty before peeking. + + return m_tokens.front(); + } + + // EnsureTokensInQueue + // . Scan until there's a valid token at the front of the queue, + // or we're sure the queue is empty. + void Scanner::EnsureTokensInQueue() { while(1) { if(!m_tokens.empty()) { Token& token = m_tokens.front(); - // return this guy if it's valid + // if this guy's valid, then we're done if(token.status == TS_VALID) - return token; + return; // here's where we clean up the impossible tokens if(token.status == TS_INVALID) { @@ -55,13 +68,11 @@ namespace YAML // no token? maybe we've actually finished if(m_endedStream) - break; + return; // no? then scan... ScanNextToken(); } - - // TODO: find something to return here, or assert (but can't do that! maybe split into two functions?) } // ScanNextToken diff --git a/src/scanner.h b/src/scanner.h index 06fd509..805b82d 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -16,16 +16,18 @@ namespace YAML Scanner(std::istream& in); ~Scanner(); - bool IsEmpty(); - void PopToken(); - Token& PeekToken(); + // token queue management (hopefully this looks kinda stl-ish) + bool empty(); + void pop(); + Token& peek(); private: // scanning - void StartStream(); - void EndStream(); + void EnsureTokensInQueue(); void ScanNextToken(); void ScanToNextToken(); + void StartStream(); + void EndStream(); Token *PushIndentTo(int column, bool sequence); void PopIndentTo(int column); diff --git a/src/sequence.cpp b/src/sequence.cpp index fed6a97..2f4ff95 100644 --- a/src/sequence.cpp +++ b/src/sequence.cpp @@ -52,9 +52,7 @@ namespace YAML Clear(); // split based on start token - Token& token = pScanner->PeekToken(); - - switch(token.type) { + switch(pScanner->peek().type) { case TT_BLOCK_SEQ_START: ParseBlock(pScanner, state); break; case TT_BLOCK_ENTRY: ParseImplicit(pScanner, state); break; case TT_FLOW_SEQ_START: ParseFlow(pScanner, state); break; @@ -64,17 +62,17 @@ namespace YAML void Sequence::ParseBlock(Scanner *pScanner, const ParserState& state) { // eat start token - pScanner->PopToken(); + pScanner->pop(); while(1) { - if(pScanner->IsEmpty()) + if(pScanner->empty()) throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ); - Token token = pScanner->PeekToken(); + Token token = pScanner->peek(); if(token.type != TT_BLOCK_ENTRY && token.type != TT_BLOCK_END) throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ); - pScanner->PopToken(); + pScanner->pop(); if(token.type == TT_BLOCK_END) break; @@ -88,15 +86,15 @@ namespace YAML { while(1) { // we're actually *allowed* to have no tokens at some point - if(pScanner->IsEmpty()) + if(pScanner->empty()) break; // and we end at anything other than a block entry - Token& token = pScanner->PeekToken(); + Token& token = pScanner->peek(); if(token.type != TT_BLOCK_ENTRY) break; - pScanner->PopToken(); + pScanner->pop(); Node *pNode = new Node; m_data.push_back(pNode); @@ -107,15 +105,15 @@ namespace YAML void Sequence::ParseFlow(Scanner *pScanner, const ParserState& state) { // eat start token - pScanner->PopToken(); + pScanner->pop(); while(1) { - if(pScanner->IsEmpty()) + if(pScanner->empty()) throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ_FLOW); // first check for end - if(pScanner->PeekToken().type == TT_FLOW_SEQ_END) { - pScanner->PopToken(); + if(pScanner->peek().type == TT_FLOW_SEQ_END) { + pScanner->pop(); break; } @@ -125,9 +123,9 @@ namespace YAML 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->PeekToken(); + Token& token = pScanner->peek(); if(token.type == TT_FLOW_ENTRY) - pScanner->PopToken(); + pScanner->pop(); else if(token.type != TT_FLOW_SEQ_END) throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ_FLOW); } diff --git a/yamlcpp.vcproj b/yamlcpp.vcproj index 7d82294..9e4fac3 100644 --- a/yamlcpp.vcproj +++ b/yamlcpp.vcproj @@ -175,10 +175,6 @@ RelativePath=".\src\iterator.cpp" > - - From 2601f5fd49133fc6a9322e8f8b0686384b2b7e6d Mon Sep 17 00:00:00 2001 From: beder Date: Thu, 31 Jul 2008 19:41:11 +0000 Subject: [PATCH 060/295] --- include/node.h | 4 ++++ src/content.h | 3 +++ src/map.cpp | 5 +++++ src/map.h | 2 ++ src/node.cpp | 8 ++++++++ src/scalar.cpp | 6 ++++++ src/scalar.h | 2 ++ src/sequence.cpp | 5 +++++ src/sequence.h | 2 ++ 9 files changed, 37 insertions(+) diff --git a/include/node.h b/include/node.h index f6a2ef6..3ddfb33 100644 --- a/include/node.h +++ b/include/node.h @@ -13,6 +13,8 @@ namespace YAML class Content; class Scanner; + enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP }; + class Node { public: @@ -23,6 +25,8 @@ namespace YAML void Parse(Scanner *pScanner, const ParserState& state); void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const; + CONTENT_TYPE GetType() const; + // accessors Iterator begin() const; Iterator end() const; diff --git a/src/content.h b/src/content.h index 3189478..9ea6a95 100644 --- a/src/content.h +++ b/src/content.h @@ -16,6 +16,8 @@ namespace YAML class Sequence; class Map; + enum CONTENT_TYPE; + class Content { public: @@ -31,6 +33,7 @@ namespace YAML virtual bool GetEnd(std::map ::const_iterator& it) const { return false; } virtual Node *GetNode(unsigned i) const { return 0; } virtual unsigned GetSize() const { return 0; } + virtual CONTENT_TYPE GetType() const = 0; // extraction virtual void Read(std::string& s) { throw InvalidScalar(); } diff --git a/src/map.cpp b/src/map.cpp index bfd8b6f..02c2da0 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -163,6 +163,11 @@ namespace YAML out << std::endl; } + CONTENT_TYPE Map::GetType() const + { + return CT_MAP; + } + int Map::Compare(Content *pContent) { return -pContent->Compare(this); diff --git a/src/map.h b/src/map.h index 3ebd3f4..5f34072 100644 --- a/src/map.h +++ b/src/map.h @@ -19,6 +19,8 @@ namespace YAML virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); + virtual CONTENT_TYPE GetType() const; + // ordering virtual int Compare(Content *pContent); virtual int Compare(Scalar *pScalar) { return 1; } diff --git a/src/node.cpp b/src/node.cpp index f67ab55..e1f323d 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -144,6 +144,14 @@ namespace YAML } } + CONTENT_TYPE Node::GetType() const + { + if(!m_pContent) + return CT_NONE; + + return m_pContent->GetType(); + } + // begin // Returns an iterator to the beginning of this (sequence or map). Iterator Node::begin() const diff --git a/src/scalar.cpp b/src/scalar.cpp index e560fb8..622813e 100644 --- a/src/scalar.cpp +++ b/src/scalar.cpp @@ -3,6 +3,7 @@ #include "scanner.h" #include "token.h" #include "exceptions.h" +#include "node.h" #include namespace YAML @@ -37,6 +38,11 @@ namespace YAML out << "\"\n"; } + CONTENT_TYPE Scalar::GetType() const + { + return CT_SCALAR; + } + void Scalar::Read(std::string& s) { s = m_data; diff --git a/src/scalar.h b/src/scalar.h index 0da9df6..8367705 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -14,6 +14,8 @@ namespace YAML virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); + virtual CONTENT_TYPE GetType() const; + // extraction virtual void Read(std::string& s); virtual void Read(int& i); diff --git a/src/sequence.cpp b/src/sequence.cpp index 2f4ff95..0c81ba4 100644 --- a/src/sequence.cpp +++ b/src/sequence.cpp @@ -150,6 +150,11 @@ namespace YAML out << std::endl; } + CONTENT_TYPE Sequence::GetType() const + { + return CT_SEQUENCE; + } + int Sequence::Compare(Content *pContent) { return -pContent->Compare(this); diff --git a/src/sequence.h b/src/sequence.h index 35b7765..8fe612c 100644 --- a/src/sequence.h +++ b/src/sequence.h @@ -22,6 +22,8 @@ namespace YAML virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); + virtual CONTENT_TYPE GetType() const; + // ordering virtual int Compare(Content *pContent); virtual int Compare(Scalar *pScalar) { return 1; } From 2d93b6ce58bfbc7d351947cad576af1e445251f1 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 7 Aug 2008 03:30:56 +0000 Subject: [PATCH 061/295] Added CMake scripts for other platforms\nFixed some bugs that gcc complained about\nFixed CR/LF vs LF bug --- CMakeLists.txt | 4 ++++ include/crt.h | 3 ++- include/exceptions.h | 1 + include/yaml.h | 3 ++- src/CMakeLists.txt | 7 +++++++ src/content.h | 6 +++--- src/exp.h | 2 +- src/map.cpp | 12 ++++------- src/map.h | 2 +- src/node.cpp | 21 ++++++++++++------- src/parser.cpp | 4 ++-- src/regex.cpp | 15 ++++++++++++- src/regex.h | 10 ++++++--- src/scalar.cpp | 5 ----- src/scalar.h | 2 +- src/sequence.cpp | 12 ++++------- src/sequence.h | 2 +- src/stream.cpp | 21 +++++++++++++++++-- src/stream.h | 10 ++++----- src/token.h | 4 ++-- yaml-reader/CMakeLists.txt | 6 ++++++ yaml-reader/main.cpp | 32 +++++++++++++--------------- yaml-reader/tests.cpp | 31 +++++++++++++++++---------- yaml-reader/tests.h | 4 ++-- yaml-reader/tests/directives.yaml | 5 +++++ yaml-reader/tests/mixed.yaml | 32 ++++++++++++++++++++++++++++ yaml-reader/tests/out.yaml | 8 +++++++ yaml-reader/tests/scalars.yaml | 35 +++++++++++++++++++++++++++++++ yaml-reader/tests/simple.yaml | 13 ++++++++++++ yaml-reader/tests/test.yaml | 3 +++ 30 files changed, 233 insertions(+), 82 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 src/CMakeLists.txt create mode 100644 yaml-reader/CMakeLists.txt create mode 100644 yaml-reader/tests/directives.yaml create mode 100644 yaml-reader/tests/mixed.yaml create mode 100644 yaml-reader/tests/out.yaml create mode 100644 yaml-reader/tests/scalars.yaml create mode 100644 yaml-reader/tests/simple.yaml create mode 100644 yaml-reader/tests/test.yaml diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..789f731 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,4 @@ +project (YAML_CPP) +set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) +add_subdirectory (src) +add_subdirectory (yaml-reader) diff --git a/include/crt.h b/include/crt.h index 82f13ec..500ef01 100644 --- a/include/crt.h +++ b/include/crt.h @@ -7,4 +7,5 @@ #include #include -#endif // _DEBUG \ No newline at end of file +#endif // _DEBUG + diff --git a/include/exceptions.h b/include/exceptions.h index 0e6031e..3185b13 100644 --- a/include/exceptions.h +++ b/include/exceptions.h @@ -10,6 +10,7 @@ namespace YAML public: ParserException(int line_, int column_, const std::string& msg_) : line(line_), column(column_), msg(msg_) {} + virtual ~ParserException() throw () {} int line, column; std::string msg; diff --git a/include/yaml.h b/include/yaml.h index de7f222..f64e07a 100644 --- a/include/yaml.h +++ b/include/yaml.h @@ -4,4 +4,5 @@ #include "parser.h" #include "node.h" #include "iterator.h" -#include "exceptions.h" \ No newline at end of file +#include "exceptions.h" + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000..d2cd7bf --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,7 @@ +set(FILES content.cpp iterator.cpp node.cpp parserstate.cpp + scalar.cpp scanscalar.cpp sequence.cpp stream.cpp + exp.cpp map.cpp parser.cpp regex.cpp scanner.cpp + scantoken.cpp simplekey.cpp) + +include_directories(${YAML_CPP_SOURCE_DIR}/include) +add_library(yaml-cpp ${FILES}) diff --git a/src/content.h b/src/content.h index 9ea6a95..166932e 100644 --- a/src/content.h +++ b/src/content.h @@ -16,8 +16,6 @@ namespace YAML class Sequence; class Map; - enum CONTENT_TYPE; - class Content { public: @@ -33,7 +31,9 @@ namespace YAML virtual bool GetEnd(std::map ::const_iterator& it) const { return false; } virtual Node *GetNode(unsigned i) const { return 0; } virtual unsigned GetSize() const { return 0; } - virtual CONTENT_TYPE GetType() const = 0; + virtual bool IsScalar() const { return false; } + virtual bool IsMap() const { return false; } + virtual bool IsSequence() const { return false; } // extraction virtual void Read(std::string& s) { throw InvalidScalar(); } diff --git a/src/exp.h b/src/exp.h index 530973e..d2bd469 100644 --- a/src/exp.h +++ b/src/exp.h @@ -14,7 +14,7 @@ namespace YAML { // misc const RegEx Blank = RegEx(' ') || RegEx('\t'); - const RegEx Break = RegEx('\n'); + const RegEx Break = RegEx('\n') || RegEx("\r\n"); const RegEx BlankOrBreak = Blank || Break; const RegEx Digit = RegEx('0', '9'); const RegEx Alpha = RegEx('a', 'z') || RegEx('A', 'Z'); diff --git a/src/map.cpp b/src/map.cpp index 02c2da0..42c381e 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -3,7 +3,8 @@ #include "node.h" #include "scanner.h" #include "token.h" -#include "exceptions.h" +#include "exceptions.h" +#include namespace YAML { @@ -142,7 +143,7 @@ namespace YAML void Map::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) { if(startedLine && !onlyOneCharOnLine) - out << std::endl; + out << "\n"; for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) { if((startedLine && !onlyOneCharOnLine) || it != m_data.begin()) { @@ -160,12 +161,7 @@ namespace YAML } if(m_data.empty()) - out << std::endl; - } - - CONTENT_TYPE Map::GetType() const - { - return CT_MAP; + out << "\n"; } int Map::Compare(Content *pContent) diff --git a/src/map.h b/src/map.h index 5f34072..8e58887 100644 --- a/src/map.h +++ b/src/map.h @@ -19,7 +19,7 @@ namespace YAML virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); - virtual CONTENT_TYPE GetType() const; + virtual bool IsMap() const { return true; } // ordering virtual int Compare(Content *pContent); diff --git a/src/node.cpp b/src/node.cpp index e1f323d..ac3cbec 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -122,23 +122,23 @@ namespace YAML // write anchor/alias if(m_anchor != "") { if(m_alias) - out << "*"; + out << std::string("*"); else - out << "&"; - out << m_anchor << " "; + out << std::string("&"); + out << m_anchor << std::string(" "); startedLine = true; onlyOneCharOnLine = false; } // write tag if(m_tag != "") { - out << "!<" << m_tag << "> "; + out << std::string("!<") << m_tag << std::string("> "); startedLine = true; onlyOneCharOnLine = false; } if(!m_pContent) { - out << std::endl; + out << std::string("\n"); } else { m_pContent->Write(out, indent, startedLine, onlyOneCharOnLine); } @@ -148,8 +148,15 @@ namespace YAML { if(!m_pContent) return CT_NONE; - - return m_pContent->GetType(); + + 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 diff --git a/src/parser.cpp b/src/parser.cpp index 7d4169d..7566526 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -121,12 +121,12 @@ namespace YAML } void Parser::PrintTokens(std::ostream& out) - { + { while(1) { if(m_pScanner->empty()) break; - out << m_pScanner->peek() << std::endl; + out << m_pScanner->peek() << "\n"; m_pScanner->pop(); } } diff --git a/src/regex.cpp b/src/regex.cpp index cbd1eb0..45ce684 100644 --- a/src/regex.cpp +++ b/src/regex.cpp @@ -1,5 +1,7 @@ #include "crt.h" -#include "regex.h" +#include "regex.h" +#include "stream.h" +#include namespace YAML { @@ -88,6 +90,11 @@ namespace YAML } bool RegEx::Matches(std::istream& in) const + { + return Match(in) >= 0; + } + + bool RegEx::Matches(Stream& in) const { return Match(in) >= 0; } @@ -106,6 +113,12 @@ namespace YAML return m_pOp->Match(str, *this); } + // Match + int RegEx::Match(Stream& in) const + { + return Match(in.stream()); + } + // Match // . The stream version does the same thing as the string version; // REMEMBER that we only match from the start of the stream! diff --git a/src/regex.h b/src/regex.h index b5429c7..6212983 100644 --- a/src/regex.h +++ b/src/regex.h @@ -5,7 +5,9 @@ #include namespace YAML -{ +{ + class Stream; + enum REGEX_OP { REGEX_EMPTY, REGEX_MATCH, REGEX_RANGE, REGEX_OR, REGEX_AND, REGEX_NOT, REGEX_SEQ }; // simplified regular expressions @@ -64,9 +66,11 @@ namespace YAML bool Matches(char ch) const; bool Matches(const std::string& str) const; - bool Matches(std::istream& in) const; + bool Matches(std::istream& in) const; + bool Matches(Stream& in) const; int Match(const std::string& str) const; - int Match(std::istream& in) const; + int Match(std::istream& in) const; + int Match(Stream& in) const; friend RegEx operator ! (const RegEx& ex); friend RegEx operator || (const RegEx& ex1, const RegEx& ex2); diff --git a/src/scalar.cpp b/src/scalar.cpp index 622813e..56edb4a 100644 --- a/src/scalar.cpp +++ b/src/scalar.cpp @@ -38,11 +38,6 @@ namespace YAML out << "\"\n"; } - CONTENT_TYPE Scalar::GetType() const - { - return CT_SCALAR; - } - void Scalar::Read(std::string& s) { s = m_data; diff --git a/src/scalar.h b/src/scalar.h index 8367705..f33f8a5 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -14,7 +14,7 @@ namespace YAML virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); - virtual CONTENT_TYPE GetType() const; + virtual bool IsScalar() const { return true; } // extraction virtual void Read(std::string& s); diff --git a/src/sequence.cpp b/src/sequence.cpp index 0c81ba4..985f979 100644 --- a/src/sequence.cpp +++ b/src/sequence.cpp @@ -2,7 +2,8 @@ #include "sequence.h" #include "node.h" #include "scanner.h" -#include "token.h" +#include "token.h" +#include namespace YAML { @@ -134,7 +135,7 @@ namespace YAML void Sequence::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) { if(startedLine && !onlyOneCharOnLine) - out << std::endl; + out << "\n"; for(unsigned i=0;i 0) { @@ -147,12 +148,7 @@ namespace YAML } if(m_data.empty()) - out << std::endl; - } - - CONTENT_TYPE Sequence::GetType() const - { - return CT_SEQUENCE; + out << "\n"; } int Sequence::Compare(Content *pContent) diff --git a/src/sequence.h b/src/sequence.h index 8fe612c..89dba85 100644 --- a/src/sequence.h +++ b/src/sequence.h @@ -22,7 +22,7 @@ namespace YAML virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); - virtual CONTENT_TYPE GetType() const; + virtual bool IsSequence() const { return true; } // ordering virtual int Compare(Content *pContent); diff --git a/src/stream.cpp b/src/stream.cpp index 38f4c8e..07e0c54 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -1,8 +1,24 @@ #include "crt.h" -#include "stream.h" +#include "stream.h" +#include namespace YAML { + int Stream::pos() const + { + return input.tellg(); + } + + char Stream::peek() + { + return input.peek(); + } + + Stream::operator bool() + { + return input.good(); + } + // get // . Extracts a character from the stream and updates our position char Stream::get() @@ -32,5 +48,6 @@ namespace YAML { for(int i=0;i> item; - std::cout << item << "\n"; - } + YAML::Parser parser(fin); + parser.PrintTokens(std::cout); } catch(YAML::Exception&) { std::cout << "Error parsing the yaml!\n"; } } -int main() -{ - _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF); - Test::RunAll(); +int main(int argc, char **argv) +{ + bool verbose = false; + for(int i=1;i files; - files.push_back("yaml-reader/tests/simple.yaml"); - files.push_back("yaml-reader/tests/mixed.yaml"); - files.push_back("yaml-reader/tests/scalars.yaml"); - files.push_back("yaml-reader/tests/directives.yaml"); + files.push_back("tests/simple.yaml"); + files.push_back("tests/mixed.yaml"); + files.push_back("tests/scalars.yaml"); + files.push_back("tests/directives.yaml"); bool passed = true; for(unsigned i=0;i namespace Test { - void RunAll(); - bool Inout(const std::string& file); + void RunAll(bool verbose); + bool Inout(const std::string& file, bool verbose); } diff --git a/yaml-reader/tests/directives.yaml b/yaml-reader/tests/directives.yaml new file mode 100644 index 0000000..ff09846 --- /dev/null +++ b/yaml-reader/tests/directives.yaml @@ -0,0 +1,5 @@ +%YAML 1.2 +%TAG ! !howdy +--- +- basic node +- ! yeah baby \ No newline at end of file diff --git a/yaml-reader/tests/mixed.yaml b/yaml-reader/tests/mixed.yaml new file mode 100644 index 0000000..88da1e7 --- /dev/null +++ b/yaml-reader/tests/mixed.yaml @@ -0,0 +1,32 @@ +- the main thing is a sequence +- here's a key: value + and another: value +- let's inline: [1, 2, 3] + and an inline map: {key: value, 243: 101} +- and multiple indents: + - here's + - a + - list + and another: + - list + - of + - things +- maybe now: + let's: get + pretty: + deep: here + in: + the: nesting + just: to + confuse: + the: heck + out: + - of + - the: parser + if: + - we + - can + - do: that + what: do + you: think? + \ No newline at end of file diff --git a/yaml-reader/tests/out.yaml b/yaml-reader/tests/out.yaml new file mode 100644 index 0000000..c02918e --- /dev/null +++ b/yaml-reader/tests/out.yaml @@ -0,0 +1,8 @@ +--- +- "basic node" +- ! "yeah baby" + +--- +- "basic node" +- !> "yeah baby" + diff --git a/yaml-reader/tests/scalars.yaml b/yaml-reader/tests/scalars.yaml new file mode 100644 index 0000000..ae0059a --- /dev/null +++ b/yaml-reader/tests/scalars.yaml @@ -0,0 +1,35 @@ +- normal scalar, but + over several lines +- | + literal scalar - so we can draw ASCII: + + - - + | - | + ------ +- > + and a folded scalar... so we + can just keep writing various + things. And if we want to keep indentation: + + we just indent a little + see, this stays indented +- >- + Here's a folded scalar + that gets chomped. +- |- + And here's a literal scalar + that gets chomped. +- >2 + Here's a folded scalar + that starts with some indentation. +- ::vector +- ": - ()" +- Up, up, and away! +- -123 +- http://example.com/foo#bar +# Inside flow collection: +- [ ::vector, + ": - ()", + "Up, up and away!", + -123, + http://example.com/foo#bar ] \ No newline at end of file diff --git a/yaml-reader/tests/simple.yaml b/yaml-reader/tests/simple.yaml new file mode 100644 index 0000000..55b2d21 --- /dev/null +++ b/yaml-reader/tests/simple.yaml @@ -0,0 +1,13 @@ +--- +just a scalar +--- +and another scalar +--- +now an end document +... +--- +and now two +... +... +--- +and that's it \ No newline at end of file diff --git a/yaml-reader/tests/test.yaml b/yaml-reader/tests/test.yaml new file mode 100644 index 0000000..64db5ef --- /dev/null +++ b/yaml-reader/tests/test.yaml @@ -0,0 +1,3 @@ +- it's just +- one thing +- after another From aa25fadf94cd21d350bb0e47416e553a5f2dd6f4 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 7 Aug 2008 03:37:16 +0000 Subject: [PATCH 062/295] Fixed struct vs. class disparity. --- src/regex.h | 8 ++++---- yaml-reader/tests/out.yaml | 8 -------- 2 files changed, 4 insertions(+), 12 deletions(-) delete mode 100644 yaml-reader/tests/out.yaml diff --git a/src/regex.h b/src/regex.h index 6212983..3efa5fb 100644 --- a/src/regex.h +++ b/src/regex.h @@ -5,8 +5,8 @@ #include namespace YAML -{ - class Stream; +{ + struct Stream; enum REGEX_OP { REGEX_EMPTY, REGEX_MATCH, REGEX_RANGE, REGEX_OR, REGEX_AND, REGEX_NOT, REGEX_SEQ }; @@ -66,10 +66,10 @@ namespace YAML bool Matches(char ch) const; bool Matches(const std::string& str) const; - bool Matches(std::istream& in) const; + bool Matches(std::istream& in) const; bool Matches(Stream& in) const; int Match(const std::string& str) const; - int Match(std::istream& in) const; + int Match(std::istream& in) const; int Match(Stream& in) const; friend RegEx operator ! (const RegEx& ex); diff --git a/yaml-reader/tests/out.yaml b/yaml-reader/tests/out.yaml deleted file mode 100644 index c02918e..0000000 --- a/yaml-reader/tests/out.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -- "basic node" -- ! "yeah baby" - ---- -- "basic node" -- !> "yeah baby" - From a57a5748f892c4567c7ba2332f2a4742c8a61c52 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 3 Sep 2008 04:37:06 +0000 Subject: [PATCH 063/295] Added the license.txt file describing the MIT license. --- license.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 license.txt diff --git a/license.txt b/license.txt new file mode 100644 index 0000000..f1ad7ae --- /dev/null +++ b/license.txt @@ -0,0 +1,19 @@ +Copyright (c) 2008 Jesse Beder. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file From 7f2c3591e32ef008b5e2e4518d4192b2135eb81f Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 3 Sep 2008 22:17:17 +0000 Subject: [PATCH 064/295] Unified line endings. --- include/crt.h | 4 ++-- include/exceptions.h | 2 +- include/yaml.h | 4 ++-- src/map.cpp | 2 +- src/node.cpp | 14 +++++++------- src/parser.cpp | 2 +- src/regex.cpp | 16 ++++++++-------- src/sequence.cpp | 2 +- src/stream.cpp | 34 +++++++++++++++++----------------- yaml-reader/main.cpp | 18 +++++++++--------- yaml-reader/tests.cpp | 20 ++++++++++---------- yaml-reader/tests/test.yaml | 2 +- 12 files changed, 60 insertions(+), 60 deletions(-) diff --git a/include/crt.h b/include/crt.h index 500ef01..ed2b68a 100644 --- a/include/crt.h +++ b/include/crt.h @@ -7,5 +7,5 @@ #include #include -#endif // _DEBUG - +#endif // _DEBUG + diff --git a/include/exceptions.h b/include/exceptions.h index 3185b13..29c555a 100644 --- a/include/exceptions.h +++ b/include/exceptions.h @@ -10,7 +10,7 @@ namespace YAML public: ParserException(int line_, int column_, const std::string& msg_) : line(line_), column(column_), msg(msg_) {} - virtual ~ParserException() throw () {} + virtual ~ParserException() throw () {} int line, column; std::string msg; diff --git a/include/yaml.h b/include/yaml.h index f64e07a..8286be4 100644 --- a/include/yaml.h +++ b/include/yaml.h @@ -4,5 +4,5 @@ #include "parser.h" #include "node.h" #include "iterator.h" -#include "exceptions.h" - +#include "exceptions.h" + diff --git a/src/map.cpp b/src/map.cpp index 42c381e..727726b 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -3,7 +3,7 @@ #include "node.h" #include "scanner.h" #include "token.h" -#include "exceptions.h" +#include "exceptions.h" #include namespace YAML diff --git a/src/node.cpp b/src/node.cpp index ac3cbec..64ec8b3 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -148,13 +148,13 @@ namespace YAML { if(!m_pContent) return CT_NONE; - - if(m_pContent->IsScalar()) - return CT_SCALAR; - else if(m_pContent->IsSequence()) - return CT_SEQUENCE; - else if(m_pContent->IsMap()) - return CT_MAP; + + 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; } diff --git a/src/parser.cpp b/src/parser.cpp index 7566526..18c7c8d 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -121,7 +121,7 @@ namespace YAML } void Parser::PrintTokens(std::ostream& out) - { + { while(1) { if(m_pScanner->empty()) break; diff --git a/src/regex.cpp b/src/regex.cpp index 45ce684..c40a087 100644 --- a/src/regex.cpp +++ b/src/regex.cpp @@ -1,6 +1,6 @@ #include "crt.h" -#include "regex.h" -#include "stream.h" +#include "regex.h" +#include "stream.h" #include namespace YAML @@ -92,8 +92,8 @@ namespace YAML bool RegEx::Matches(std::istream& in) const { return Match(in) >= 0; - } - + } + bool RegEx::Matches(Stream& in) const { return Match(in) >= 0; @@ -113,12 +113,12 @@ namespace YAML return m_pOp->Match(str, *this); } - // Match + // Match int RegEx::Match(Stream& in) const - { + { return Match(in.stream()); - } - + } + // Match // . The stream version does the same thing as the string version; // REMEMBER that we only match from the start of the stream! diff --git a/src/sequence.cpp b/src/sequence.cpp index 985f979..f997a79 100644 --- a/src/sequence.cpp +++ b/src/sequence.cpp @@ -2,7 +2,7 @@ #include "sequence.h" #include "node.h" #include "scanner.h" -#include "token.h" +#include "token.h" #include namespace YAML diff --git a/src/stream.cpp b/src/stream.cpp index 07e0c54..73d4129 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -1,24 +1,24 @@ #include "crt.h" -#include "stream.h" +#include "stream.h" #include namespace YAML { - int Stream::pos() const - { - return input.tellg(); - } - - char Stream::peek() - { - return input.peek(); - } - - Stream::operator bool() - { - return input.good(); + int Stream::pos() const + { + return input.tellg(); } - + + char Stream::peek() + { + return input.peek(); + } + + Stream::operator bool() + { + return input.good(); + } + // get // . Extracts a character from the stream and updates our position char Stream::get() @@ -48,6 +48,6 @@ namespace YAML { for(int i=0;i Date: Wed, 3 Sep 2008 22:19:27 +0000 Subject: [PATCH 065/295] Fixed some gcc warnings. --- include/node.h | 2 +- src/iterpriv.h | 4 ++-- yaml-reader/main.cpp | 4 +++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/include/node.h b/include/node.h index 3ddfb33..6d604c9 100644 --- a/include/node.h +++ b/include/node.h @@ -85,8 +85,8 @@ namespace YAML void ParseAlias(Scanner *pScanner, const ParserState& state); private: - bool m_alias; std::string m_anchor, m_tag; Content *m_pContent; + bool m_alias; }; } diff --git a/src/iterpriv.h b/src/iterpriv.h index 80d7d6a..5c29366 100644 --- a/src/iterpriv.h +++ b/src/iterpriv.h @@ -13,8 +13,8 @@ namespace YAML struct IterPriv { IterPriv(): type(IT_NONE) {} - IterPriv(std::vector ::const_iterator it): seqIter(it), type(IT_SEQ) {} - IterPriv(std::map ::const_iterator it): mapIter(it), type(IT_MAP) {} + IterPriv(std::vector ::const_iterator it): type(IT_SEQ), seqIter(it) {} + IterPriv(std::map ::const_iterator it): type(IT_MAP), mapIter(it) {} enum ITER_TYPE { IT_NONE, IT_SEQ, IT_MAP }; ITER_TYPE type; diff --git a/yaml-reader/main.cpp b/yaml-reader/main.cpp index 9ee3f0e..1d32cba 100644 --- a/yaml-reader/main.cpp +++ b/yaml-reader/main.cpp @@ -3,11 +3,13 @@ #include #include +#ifdef _MSC_VER #ifdef _DEBUG #pragma comment(lib, "yamlcppd.lib") #else #pragma comment(lib, "yamlcpp.lib") -#endif +#endif // _DEBUG +#endif // _MSC_VER void run() { From b43f827188284f393a367a867bd76f6d8f6bf538 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 3 Sep 2008 22:20:39 +0000 Subject: [PATCH 066/295] Set the eol style to native for all files. --- include/crt.h | 22 +- include/exceptions.h | 118 ++--- include/iterator.h | 60 +-- include/node.h | 184 +++---- include/parser.h | 84 ++-- include/parserstate.h | 40 +- include/yaml.h | 16 +- src/content.cpp | 26 +- src/content.h | 110 ++-- src/exp.cpp | 226 ++++----- src/exp.h | 142 +++--- src/iterator.cpp | 216 ++++---- src/iterpriv.h | 50 +- src/ltnode.h | 20 +- src/map.cpp | 392 +++++++-------- src/map.h | 76 +-- src/node.cpp | 634 +++++++++++------------ src/parser.cpp | 266 +++++----- src/parserstate.cpp | 52 +- src/regex.cpp | 612 +++++++++++----------- src/regex.h | 180 +++---- src/scalar.cpp | 216 ++++---- src/scalar.h | 74 +-- src/scanner.cpp | 552 ++++++++++---------- src/scanner.h | 170 +++---- src/scanscalar.cpp | 308 ++++++------ src/scanscalar.h | 70 +-- src/scantoken.cpp | 810 +++++++++++++++--------------- src/sequence.cpp | 350 ++++++------- src/sequence.h | 82 +-- src/simplekey.cpp | 204 ++++---- src/stream.cpp | 106 ++-- src/stream.h | 50 +- src/token.h | 136 ++--- yaml-reader/main.cpp | 82 +-- yaml-reader/tests.cpp | 176 +++---- yaml-reader/tests.h | 12 +- yaml-reader/tests/directives.yaml | 8 +- yaml-reader/tests/mixed.yaml | 62 +-- yaml-reader/tests/scalars.yaml | 68 +-- yaml-reader/tests/simple.yaml | 24 +- yaml-reader/tests/test.yaml | 6 +- 42 files changed, 3546 insertions(+), 3546 deletions(-) diff --git a/include/crt.h b/include/crt.h index ed2b68a..5c6f96a 100644 --- a/include/crt.h +++ b/include/crt.h @@ -1,11 +1,11 @@ -#pragma once - -// for detecting memory leaks -#ifdef _DEBUG - -#define _CRTDBG_MAP_ALLOC -#include -#include - -#endif // _DEBUG - +#pragma once + +// for detecting memory leaks +#ifdef _DEBUG + +#define _CRTDBG_MAP_ALLOC +#include +#include + +#endif // _DEBUG + diff --git a/include/exceptions.h b/include/exceptions.h index 29c555a..427088a 100644 --- a/include/exceptions.h +++ b/include/exceptions.h @@ -1,59 +1,59 @@ -#pragma once - -#include -#include - -namespace YAML -{ - class Exception: public std::exception {}; - class ParserException: public Exception { - public: - ParserException(int line_, int column_, const std::string& msg_) - : line(line_), column(column_), msg(msg_) {} - virtual ~ParserException() throw () {} - - int line, column; - std::string msg; - }; - - class RepresentationException: public Exception {}; - - // representation exceptions - class InvalidScalar: public RepresentationException {}; - class BadDereference: public RepresentationException {}; - - // error messages - namespace ErrorMsg - { - const std::string YAML_DIRECTIVE_ARGS = "YAML directives must have exactly one argument"; - const std::string YAML_VERSION = "bad YAML version: "; - const std::string YAML_MAJOR_VERSION = "YAML major version too large"; - const std::string TAG_DIRECTIVE_ARGS = "TAG directives must have exactly two arguments"; - const std::string END_OF_MAP = "end of map not found"; - const std::string END_OF_MAP_FLOW = "end of map flow not found"; - const std::string END_OF_SEQ = "end of sequence not found"; - const std::string END_OF_SEQ_FLOW = "end of sequence flow not found"; - const std::string MULTIPLE_TAGS = "cannot assign multiple tags to the same node"; - const std::string MULTIPLE_ANCHORS = "cannot assign multiple anchors to the same node"; - const std::string MULTIPLE_ALIASES = "cannot assign multiple aliases to the same node"; - const std::string ALIAS_CONTENT = "aliases can't have any content, *including* tags"; - const std::string INVALID_HEX = "bad character found while scanning hex number"; - const std::string INVALID_UNICODE = "invalid unicode: "; - const std::string INVALID_ESCAPE = "unknown escape character: "; - const std::string UNKNOWN_TOKEN = "unknown token"; - const std::string DOC_IN_SCALAR = "illegal document indicator in scalar"; - const std::string EOF_IN_SCALAR = "illegal EOF in scalar"; - const std::string CHAR_IN_SCALAR = "illegal character in scalar"; - const std::string TAB_IN_INDENTATION = "illegal tab when looking for indentation"; - const std::string FLOW_END = "illegal flow end"; - const std::string BLOCK_ENTRY = "illegal block entry"; - const std::string MAP_KEY = "illegal map key"; - const std::string MAP_VALUE = "illegal map value"; - const std::string ALIAS_NOT_FOUND = "alias not found after *"; - const std::string ANCHOR_NOT_FOUND = "anchor not found after &"; - const std::string CHAR_IN_ALIAS = "illegal character found while scanning alias"; - const std::string CHAR_IN_ANCHOR = "illegal character found while scanning anchor"; - const std::string ZERO_INDENT_IN_BLOCK = "cannot set zero indentation for a block scalar"; - const std::string CHAR_IN_BLOCK = "unexpected character in block scalar"; - } -} +#pragma once + +#include +#include + +namespace YAML +{ + class Exception: public std::exception {}; + class ParserException: public Exception { + public: + ParserException(int line_, int column_, const std::string& msg_) + : line(line_), column(column_), msg(msg_) {} + virtual ~ParserException() throw () {} + + int line, column; + std::string msg; + }; + + class RepresentationException: public Exception {}; + + // representation exceptions + class InvalidScalar: public RepresentationException {}; + class BadDereference: public RepresentationException {}; + + // error messages + namespace ErrorMsg + { + const std::string YAML_DIRECTIVE_ARGS = "YAML directives must have exactly one argument"; + const std::string YAML_VERSION = "bad YAML version: "; + const std::string YAML_MAJOR_VERSION = "YAML major version too large"; + const std::string TAG_DIRECTIVE_ARGS = "TAG directives must have exactly two arguments"; + const std::string END_OF_MAP = "end of map not found"; + const std::string END_OF_MAP_FLOW = "end of map flow not found"; + const std::string END_OF_SEQ = "end of sequence not found"; + const std::string END_OF_SEQ_FLOW = "end of sequence flow not found"; + const std::string MULTIPLE_TAGS = "cannot assign multiple tags to the same node"; + const std::string MULTIPLE_ANCHORS = "cannot assign multiple anchors to the same node"; + const std::string MULTIPLE_ALIASES = "cannot assign multiple aliases to the same node"; + const std::string ALIAS_CONTENT = "aliases can't have any content, *including* tags"; + const std::string INVALID_HEX = "bad character found while scanning hex number"; + const std::string INVALID_UNICODE = "invalid unicode: "; + const std::string INVALID_ESCAPE = "unknown escape character: "; + const std::string UNKNOWN_TOKEN = "unknown token"; + const std::string DOC_IN_SCALAR = "illegal document indicator in scalar"; + const std::string EOF_IN_SCALAR = "illegal EOF in scalar"; + const std::string CHAR_IN_SCALAR = "illegal character in scalar"; + const std::string TAB_IN_INDENTATION = "illegal tab when looking for indentation"; + const std::string FLOW_END = "illegal flow end"; + const std::string BLOCK_ENTRY = "illegal block entry"; + const std::string MAP_KEY = "illegal map key"; + const std::string MAP_VALUE = "illegal map value"; + const std::string ALIAS_NOT_FOUND = "alias not found after *"; + const std::string ANCHOR_NOT_FOUND = "anchor not found after &"; + const std::string CHAR_IN_ALIAS = "illegal character found while scanning alias"; + const std::string CHAR_IN_ANCHOR = "illegal character found while scanning anchor"; + const std::string ZERO_INDENT_IN_BLOCK = "cannot set zero indentation for a block scalar"; + const std::string CHAR_IN_BLOCK = "unexpected character in block scalar"; + } +} diff --git a/include/iterator.h b/include/iterator.h index afaddb6..3dbd9ee 100644 --- a/include/iterator.h +++ b/include/iterator.h @@ -1,30 +1,30 @@ -#pragma once - -namespace YAML -{ - class Node; - struct IterPriv; - - class Iterator - { - public: - Iterator(); - Iterator(IterPriv *pData); - Iterator(const Iterator& rhs); - ~Iterator(); - - Iterator& operator = (const Iterator& rhs); - Iterator& operator ++ (); - Iterator operator ++ (int); - const Node& operator * () const; - const Node *operator -> () const; - const Node& first() const; - const Node& second() const; - - friend bool operator == (const Iterator& it, const Iterator& jt); - friend bool operator != (const Iterator& it, const Iterator& jt); - - private: - IterPriv *m_pData; - }; -} +#pragma once + +namespace YAML +{ + class Node; + struct IterPriv; + + class Iterator + { + public: + Iterator(); + Iterator(IterPriv *pData); + Iterator(const Iterator& rhs); + ~Iterator(); + + Iterator& operator = (const Iterator& rhs); + Iterator& operator ++ (); + Iterator operator ++ (int); + const Node& operator * () const; + const Node *operator -> () const; + const Node& first() const; + const Node& second() const; + + friend bool operator == (const Iterator& it, const Iterator& jt); + friend bool operator != (const Iterator& it, const Iterator& jt); + + private: + IterPriv *m_pData; + }; +} diff --git a/include/node.h b/include/node.h index 6d604c9..8f1a739 100644 --- a/include/node.h +++ b/include/node.h @@ -1,92 +1,92 @@ -#pragma once - -#include -#include -#include -#include -#include "parserstate.h" -#include "exceptions.h" -#include "iterator.h" - -namespace YAML -{ - class Content; - class Scanner; - - enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP }; - - class Node - { - public: - Node(); - ~Node(); - - void Clear(); - void Parse(Scanner *pScanner, const ParserState& state); - void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const; - - CONTENT_TYPE GetType() const; - - // accessors - Iterator begin() const; - Iterator end() const; - unsigned size() const; - - template - const Node& GetValue(const T& key) const { - if(!m_pContent) - throw BadDereference(); - - for(Iterator it=begin();it!=end();++it) { - T t; - try { - it.first() >> t; - if(key == t) - return it.second(); - } catch(RepresentationException&) { - } - } - - throw BadDereference(); - } - - template - const Node& operator [] (const T& key) const { - return GetValue(key); - } - - const Node& operator [] (const char *key) const { - return GetValue(std::string(key)); - } - - const Node& operator [] (unsigned u) const; - const Node& operator [] (int i) const; - - // extraction - friend void operator >> (const Node& node, std::string& s); - friend void operator >> (const Node& node, int& i); - friend void operator >> (const Node& node, unsigned& u); - friend void operator >> (const Node& node, long& l); - friend void operator >> (const Node& node, float& f); - friend void operator >> (const Node& node, double& d); - friend void operator >> (const Node& node, char& c); - - // insertion - friend std::ostream& operator << (std::ostream& out, const Node& node); - - // ordering - int Compare(const Node& rhs) const; - friend bool operator < (const Node& n1, const Node& n2); - - private: - void ParseHeader(Scanner *pScanner, const ParserState& state); - void ParseTag(Scanner *pScanner, const ParserState& state); - void ParseAnchor(Scanner *pScanner, const ParserState& state); - void ParseAlias(Scanner *pScanner, const ParserState& state); - - private: - std::string m_anchor, m_tag; - Content *m_pContent; - bool m_alias; - }; -} +#pragma once + +#include +#include +#include +#include +#include "parserstate.h" +#include "exceptions.h" +#include "iterator.h" + +namespace YAML +{ + class Content; + class Scanner; + + enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP }; + + class Node + { + public: + Node(); + ~Node(); + + void Clear(); + void Parse(Scanner *pScanner, const ParserState& state); + void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const; + + CONTENT_TYPE GetType() const; + + // accessors + Iterator begin() const; + Iterator end() const; + unsigned size() const; + + template + const Node& GetValue(const T& key) const { + if(!m_pContent) + throw BadDereference(); + + for(Iterator it=begin();it!=end();++it) { + T t; + try { + it.first() >> t; + if(key == t) + return it.second(); + } catch(RepresentationException&) { + } + } + + throw BadDereference(); + } + + template + const Node& operator [] (const T& key) const { + return GetValue(key); + } + + const Node& operator [] (const char *key) const { + return GetValue(std::string(key)); + } + + const Node& operator [] (unsigned u) const; + const Node& operator [] (int i) const; + + // extraction + friend void operator >> (const Node& node, std::string& s); + friend void operator >> (const Node& node, int& i); + friend void operator >> (const Node& node, unsigned& u); + friend void operator >> (const Node& node, long& l); + friend void operator >> (const Node& node, float& f); + friend void operator >> (const Node& node, double& d); + friend void operator >> (const Node& node, char& c); + + // insertion + friend std::ostream& operator << (std::ostream& out, const Node& node); + + // ordering + int Compare(const Node& rhs) const; + friend bool operator < (const Node& n1, const Node& n2); + + private: + void ParseHeader(Scanner *pScanner, const ParserState& state); + void ParseTag(Scanner *pScanner, const ParserState& state); + void ParseAnchor(Scanner *pScanner, const ParserState& state); + void ParseAlias(Scanner *pScanner, const ParserState& state); + + private: + std::string m_anchor, m_tag; + Content *m_pContent; + bool m_alias; + }; +} diff --git a/include/parser.h b/include/parser.h index ef4d656..83f611b 100644 --- a/include/parser.h +++ b/include/parser.h @@ -1,42 +1,42 @@ -#pragma once - -#include -#include -#include -#include -#include "node.h" -#include "parserstate.h" - -namespace YAML -{ - class Scanner; - struct Token; - - class Parser - { - public: - Parser(std::istream& in); - ~Parser(); - - operator bool() const; - - void Load(std::istream& in); - void GetNextDocument(Node& document); - void PrintTokens(std::ostream& out); - - private: - void ParseDirectives(); - void HandleDirective(Token *pToken); - void HandleYamlDirective(Token *pToken); - void HandleTagDirective(Token *pToken); - - private: - // can't copy this - Parser(const Parser& rhs) {} - Parser& operator = (const Parser& rhs) { return *this; } - - private: - Scanner *m_pScanner; - ParserState m_state; - }; -} +#pragma once + +#include +#include +#include +#include +#include "node.h" +#include "parserstate.h" + +namespace YAML +{ + class Scanner; + struct Token; + + class Parser + { + public: + Parser(std::istream& in); + ~Parser(); + + operator bool() const; + + void Load(std::istream& in); + void GetNextDocument(Node& document); + void PrintTokens(std::ostream& out); + + private: + void ParseDirectives(); + void HandleDirective(Token *pToken); + void HandleYamlDirective(Token *pToken); + void HandleTagDirective(Token *pToken); + + private: + // can't copy this + Parser(const Parser& rhs) {} + Parser& operator = (const Parser& rhs) { return *this; } + + private: + Scanner *m_pScanner; + ParserState m_state; + }; +} diff --git a/include/parserstate.h b/include/parserstate.h index e98667d..f8eb97f 100644 --- a/include/parserstate.h +++ b/include/parserstate.h @@ -1,20 +1,20 @@ -#pragma once - -#include -#include - -namespace YAML -{ - struct Version { - int major, minor; - }; - - struct ParserState - { - Version version; - std::map tags; - - void Reset(); - std::string TranslateTag(const std::string& handle) const; - }; -} +#pragma once + +#include +#include + +namespace YAML +{ + struct Version { + int major, minor; + }; + + struct ParserState + { + Version version; + std::map tags; + + void Reset(); + std::string TranslateTag(const std::string& handle) const; + }; +} diff --git a/include/yaml.h b/include/yaml.h index 8286be4..f7cd1e7 100644 --- a/include/yaml.h +++ b/include/yaml.h @@ -1,8 +1,8 @@ -#pragma once - -#include "crt.h" -#include "parser.h" -#include "node.h" -#include "iterator.h" -#include "exceptions.h" - +#pragma once + +#include "crt.h" +#include "parser.h" +#include "node.h" +#include "iterator.h" +#include "exceptions.h" + diff --git a/src/content.cpp b/src/content.cpp index 4995729..850dcab 100644 --- a/src/content.cpp +++ b/src/content.cpp @@ -1,13 +1,13 @@ -#include "crt.h" -#include "content.h" - -namespace YAML -{ - Content::Content() - { - } - - Content::~Content() - { - } -} +#include "crt.h" +#include "content.h" + +namespace YAML +{ + Content::Content() + { + } + + Content::~Content() + { + } +} diff --git a/src/content.h b/src/content.h index 166932e..b7a5da9 100644 --- a/src/content.h +++ b/src/content.h @@ -1,55 +1,55 @@ -#pragma once - -#include -#include -#include -#include "parserstate.h" -#include "exceptions.h" -#include "ltnode.h" - -namespace YAML -{ - class Scanner; - class Parser; - class Node; - class Scalar; - class Sequence; - class Map; - - class Content - { - public: - Content(); - virtual ~Content(); - - virtual void Parse(Scanner *pScanner, const ParserState& state) = 0; - virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) = 0; - - virtual bool GetBegin(std::vector ::const_iterator& it) const { return false; } - virtual bool GetBegin(std::map ::const_iterator& it) const { return false; } - virtual bool GetEnd(std::vector ::const_iterator& it) const { return false; } - virtual bool GetEnd(std::map ::const_iterator& it) const { return false; } - virtual Node *GetNode(unsigned i) const { return 0; } - virtual unsigned GetSize() const { return 0; } - virtual bool IsScalar() const { return false; } - virtual bool IsMap() const { return false; } - virtual bool IsSequence() const { return false; } - - // extraction - virtual void Read(std::string& s) { throw InvalidScalar(); } - virtual void Read(int& i) { throw InvalidScalar(); } - virtual void Read(unsigned& u) { throw InvalidScalar(); } - virtual void Read(long& l) { throw InvalidScalar(); } - virtual void Read(float& f) { throw InvalidScalar(); } - virtual void Read(double& d) { throw InvalidScalar(); } - virtual void Read(char& c) { throw InvalidScalar(); } - - // ordering - virtual int Compare(Content *pContent) { return 0; } - virtual int Compare(Scalar *pScalar) { return 0; } - virtual int Compare(Sequence *pSeq) { return 0; } - virtual int Compare(Map *pMap) { return 0; } - - protected: - }; -} +#pragma once + +#include +#include +#include +#include "parserstate.h" +#include "exceptions.h" +#include "ltnode.h" + +namespace YAML +{ + class Scanner; + class Parser; + class Node; + class Scalar; + class Sequence; + class Map; + + class Content + { + public: + Content(); + virtual ~Content(); + + virtual void Parse(Scanner *pScanner, const ParserState& state) = 0; + virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) = 0; + + virtual bool GetBegin(std::vector ::const_iterator& it) const { return false; } + virtual bool GetBegin(std::map ::const_iterator& it) const { return false; } + virtual bool GetEnd(std::vector ::const_iterator& it) const { return false; } + virtual bool GetEnd(std::map ::const_iterator& it) const { return false; } + virtual Node *GetNode(unsigned i) const { return 0; } + virtual unsigned GetSize() const { return 0; } + virtual bool IsScalar() const { return false; } + virtual bool IsMap() const { return false; } + virtual bool IsSequence() const { return false; } + + // extraction + virtual void Read(std::string& s) { throw InvalidScalar(); } + virtual void Read(int& i) { throw InvalidScalar(); } + virtual void Read(unsigned& u) { throw InvalidScalar(); } + virtual void Read(long& l) { throw InvalidScalar(); } + virtual void Read(float& f) { throw InvalidScalar(); } + virtual void Read(double& d) { throw InvalidScalar(); } + virtual void Read(char& c) { throw InvalidScalar(); } + + // ordering + virtual int Compare(Content *pContent) { return 0; } + virtual int Compare(Scalar *pScalar) { return 0; } + virtual int Compare(Sequence *pSeq) { return 0; } + virtual int Compare(Map *pMap) { return 0; } + + protected: + }; +} diff --git a/src/exp.cpp b/src/exp.cpp index 8ce2af7..7148acc 100644 --- a/src/exp.cpp +++ b/src/exp.cpp @@ -1,113 +1,113 @@ -#include "crt.h" -#include "exp.h" -#include "exceptions.h" -#include - -namespace YAML -{ - namespace Exp - { - unsigned ParseHex(const std::string& str, int line, int column) - { - unsigned value = 0; - for(unsigned i=0;i= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) { - std::stringstream msg; - msg << ErrorMsg::INVALID_UNICODE << value; - throw ParserException(in.line, in.column, msg.str()); - } - - // now break it up into chars - if(value <= 0x7F) - return Str(value); - else if(value <= 0x7FF) - return Str(0xC0 + (value >> 6)) + Str(0x80 + (value & 0x3F)); - else if(value <= 0xFFFF) - return Str(0xE0 + (value >> 12)) + Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F)); - else - return Str(0xF0 + (value >> 18)) + Str(0x80 + ((value >> 12) & 0x3F)) + - Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F)); - } - - // Escape - // . Escapes the sequence starting 'in' (it must begin with a '\' or single quote) - // and returns the result. - // . Throws if it's an unknown escape character. - std::string Escape(Stream& in) - { - // eat slash - char escape = in.get(); - - // switch on escape character - char ch = in.get(); - - // first do single quote, since it's easier - if(escape == '\'' && ch == '\'') - return "\'"; - - // now do the slash (we're not gonna check if it's a slash - you better pass one!) - switch(ch) { - case '0': return "\0"; - case 'a': return "\x07"; - case 'b': return "\x08"; - case 't': - case '\t': return "\x09"; - case 'n': return "\x0A"; - case 'v': return "\x0B"; - case 'f': return "\x0C"; - case 'r': return "\x0D"; - case 'e': return "\x1B"; - case ' ': return "\x20"; - case '\"': return "\""; - case '\'': return "\'"; - case '\\': return "\\"; - case 'N': return "\xC2\x85"; // NEL (#x85) - case '_': return "\xC2\xA0"; // #xA0 - case 'L': return "\xE2\x80\xA8"; // LS (#x2028) - case 'P': return "\xE2\x80\xA9"; // PS (#x2029) - case 'x': return Escape(in, 2); - case 'u': return Escape(in, 4); - case 'U': return Escape(in, 8); - } - - std::stringstream msg; - throw ParserException(in.line, in.column, ErrorMsg::INVALID_ESCAPE + ch); - } - } -} +#include "crt.h" +#include "exp.h" +#include "exceptions.h" +#include + +namespace YAML +{ + namespace Exp + { + unsigned ParseHex(const std::string& str, int line, int column) + { + unsigned value = 0; + for(unsigned i=0;i= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) { + std::stringstream msg; + msg << ErrorMsg::INVALID_UNICODE << value; + throw ParserException(in.line, in.column, msg.str()); + } + + // now break it up into chars + if(value <= 0x7F) + return Str(value); + else if(value <= 0x7FF) + return Str(0xC0 + (value >> 6)) + Str(0x80 + (value & 0x3F)); + else if(value <= 0xFFFF) + return Str(0xE0 + (value >> 12)) + Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F)); + else + return Str(0xF0 + (value >> 18)) + Str(0x80 + ((value >> 12) & 0x3F)) + + Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F)); + } + + // Escape + // . Escapes the sequence starting 'in' (it must begin with a '\' or single quote) + // and returns the result. + // . Throws if it's an unknown escape character. + std::string Escape(Stream& in) + { + // eat slash + char escape = in.get(); + + // switch on escape character + char ch = in.get(); + + // first do single quote, since it's easier + if(escape == '\'' && ch == '\'') + return "\'"; + + // now do the slash (we're not gonna check if it's a slash - you better pass one!) + switch(ch) { + case '0': return "\0"; + case 'a': return "\x07"; + case 'b': return "\x08"; + case 't': + case '\t': return "\x09"; + case 'n': return "\x0A"; + case 'v': return "\x0B"; + case 'f': return "\x0C"; + case 'r': return "\x0D"; + case 'e': return "\x1B"; + case ' ': return "\x20"; + case '\"': return "\""; + case '\'': return "\'"; + case '\\': return "\\"; + case 'N': return "\xC2\x85"; // NEL (#x85) + case '_': return "\xC2\xA0"; // #xA0 + case 'L': return "\xE2\x80\xA8"; // LS (#x2028) + case 'P': return "\xE2\x80\xA9"; // PS (#x2029) + case 'x': return Escape(in, 2); + case 'u': return Escape(in, 4); + case 'U': return Escape(in, 8); + } + + std::stringstream msg; + throw ParserException(in.line, in.column, ErrorMsg::INVALID_ESCAPE + ch); + } + } +} diff --git a/src/exp.h b/src/exp.h index d2bd469..7811bd2 100644 --- a/src/exp.h +++ b/src/exp.h @@ -1,71 +1,71 @@ -#pragma once - -#include "regex.h" -#include -#include -#include "stream.h" - -namespace YAML -{ - //////////////////////////////////////////////////////////////////////////////// - // Here we store a bunch of expressions for matching different parts of the file. - - namespace Exp - { - // misc - const RegEx Blank = RegEx(' ') || RegEx('\t'); - const RegEx Break = RegEx('\n') || RegEx("\r\n"); - const RegEx BlankOrBreak = Blank || Break; - const RegEx Digit = RegEx('0', '9'); - const RegEx Alpha = RegEx('a', 'z') || RegEx('A', 'Z'); - const RegEx AlphaNumeric = Alpha || Digit; - const RegEx Hex = Digit || RegEx('A', 'F') || RegEx('a', 'f'); - - // actual tags - - const RegEx DocStart = RegEx("---") + (BlankOrBreak || RegEx(EOF) || RegEx()); - const RegEx DocEnd = RegEx("...") + (BlankOrBreak || RegEx(EOF) || RegEx()); - const RegEx DocIndicator = DocStart || DocEnd; - const RegEx BlockEntry = RegEx('-') + (BlankOrBreak || RegEx(EOF)); - const RegEx Key = RegEx('?'), - KeyInFlow = RegEx('?') + BlankOrBreak; - const RegEx Value = RegEx(':') + BlankOrBreak, - ValueInFlow = RegEx(':') + BlankOrBreak; - const RegEx Comment = RegEx('#'); - const RegEx AnchorEnd = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak; - - // Plain scalar rules: - // . Cannot start with a blank. - // . Can never start with any of , [ ] { } # & * ! | > \' \" % @ ` - // . In the block context - ? : must be not be followed with a space. - // . In the flow context ? is illegal and : and - must not be followed with a space. - const RegEx PlainScalar = !(BlankOrBreak || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:", REGEX_OR) + Blank)), - PlainScalarInFlow = !(BlankOrBreak || RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-:", REGEX_OR) + Blank)); - const RegEx EndScalar = RegEx(':') + BlankOrBreak, - EndScalarInFlow = (RegEx(':') + BlankOrBreak) || RegEx(",?[]{}", REGEX_OR); - - const RegEx EscSingleQuote = RegEx("\'\'"); - const RegEx EscBreak = RegEx('\\') + Break; - - const RegEx ChompIndicator = RegEx("+-", REGEX_OR); - const RegEx Chomp = (ChompIndicator + Digit) || (Digit + ChompIndicator) || ChompIndicator || Digit; - - // and some functions - std::string Escape(Stream& in); - } - - namespace Keys - { - const char Directive = '%'; - const char FlowSeqStart = '['; - const char FlowSeqEnd = ']'; - const char FlowMapStart = '{'; - const char FlowMapEnd = '}'; - const char FlowEntry = ','; - const char Alias = '*'; - const char Anchor = '&'; - const char Tag = '!'; - const char LiteralScalar = '|'; - const char FoldedScalar = '>'; - } -} +#pragma once + +#include "regex.h" +#include +#include +#include "stream.h" + +namespace YAML +{ + //////////////////////////////////////////////////////////////////////////////// + // Here we store a bunch of expressions for matching different parts of the file. + + namespace Exp + { + // misc + const RegEx Blank = RegEx(' ') || RegEx('\t'); + const RegEx Break = RegEx('\n') || RegEx("\r\n"); + const RegEx BlankOrBreak = Blank || Break; + const RegEx Digit = RegEx('0', '9'); + const RegEx Alpha = RegEx('a', 'z') || RegEx('A', 'Z'); + const RegEx AlphaNumeric = Alpha || Digit; + const RegEx Hex = Digit || RegEx('A', 'F') || RegEx('a', 'f'); + + // actual tags + + const RegEx DocStart = RegEx("---") + (BlankOrBreak || RegEx(EOF) || RegEx()); + const RegEx DocEnd = RegEx("...") + (BlankOrBreak || RegEx(EOF) || RegEx()); + const RegEx DocIndicator = DocStart || DocEnd; + const RegEx BlockEntry = RegEx('-') + (BlankOrBreak || RegEx(EOF)); + const RegEx Key = RegEx('?'), + KeyInFlow = RegEx('?') + BlankOrBreak; + const RegEx Value = RegEx(':') + BlankOrBreak, + ValueInFlow = RegEx(':') + BlankOrBreak; + const RegEx Comment = RegEx('#'); + const RegEx AnchorEnd = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak; + + // Plain scalar rules: + // . Cannot start with a blank. + // . Can never start with any of , [ ] { } # & * ! | > \' \" % @ ` + // . In the block context - ? : must be not be followed with a space. + // . In the flow context ? is illegal and : and - must not be followed with a space. + const RegEx PlainScalar = !(BlankOrBreak || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:", REGEX_OR) + Blank)), + PlainScalarInFlow = !(BlankOrBreak || RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-:", REGEX_OR) + Blank)); + const RegEx EndScalar = RegEx(':') + BlankOrBreak, + EndScalarInFlow = (RegEx(':') + BlankOrBreak) || RegEx(",?[]{}", REGEX_OR); + + const RegEx EscSingleQuote = RegEx("\'\'"); + const RegEx EscBreak = RegEx('\\') + Break; + + const RegEx ChompIndicator = RegEx("+-", REGEX_OR); + const RegEx Chomp = (ChompIndicator + Digit) || (Digit + ChompIndicator) || ChompIndicator || Digit; + + // and some functions + std::string Escape(Stream& in); + } + + namespace Keys + { + const char Directive = '%'; + const char FlowSeqStart = '['; + const char FlowSeqEnd = ']'; + const char FlowMapStart = '{'; + const char FlowMapEnd = '}'; + const char FlowEntry = ','; + const char Alias = '*'; + const char Anchor = '&'; + const char Tag = '!'; + const char LiteralScalar = '|'; + const char FoldedScalar = '>'; + } +} diff --git a/src/iterator.cpp b/src/iterator.cpp index 1ce3dc0..51e52a3 100644 --- a/src/iterator.cpp +++ b/src/iterator.cpp @@ -1,108 +1,108 @@ -#include "crt.h" -#include "node.h" -#include "exceptions.h" -#include "iterpriv.h" - -namespace YAML -{ - Iterator::Iterator(): m_pData(0) - { - m_pData = new IterPriv; - } - - Iterator::Iterator(IterPriv *pData): m_pData(pData) - { - } - - Iterator::Iterator(const Iterator& rhs): m_pData(0) - { - m_pData = new IterPriv(*rhs.m_pData); - } - - Iterator& Iterator::operator = (const Iterator& rhs) - { - if(this == &rhs) - return *this; - - delete m_pData; - m_pData = new IterPriv(*rhs.m_pData); - return *this; - } - - Iterator::~Iterator() - { - delete m_pData; - } - - Iterator& Iterator::operator ++ () - { - if(m_pData->type == IterPriv::IT_SEQ) - ++m_pData->seqIter; - else if(m_pData->type == IterPriv::IT_MAP) - ++m_pData->mapIter; - - return *this; - } - - Iterator Iterator::operator ++ (int) - { - Iterator temp = *this; - - if(m_pData->type == IterPriv::IT_SEQ) - ++m_pData->seqIter; - else if(m_pData->type == IterPriv::IT_MAP) - ++m_pData->mapIter; - - return temp; - } - - const Node& Iterator::operator * () const - { - if(m_pData->type == IterPriv::IT_SEQ) - return **m_pData->seqIter; - - throw BadDereference(); - } - - const Node *Iterator::operator -> () const - { - if(m_pData->type == IterPriv::IT_SEQ) - return *m_pData->seqIter; - - throw BadDereference(); - } - - const Node& Iterator::first() const - { - if(m_pData->type == IterPriv::IT_MAP) - return *m_pData->mapIter->first; - - throw BadDereference(); - } - - const Node& Iterator::second() const - { - if(m_pData->type == IterPriv::IT_MAP) - return *m_pData->mapIter->second; - - throw BadDereference(); - } - - bool operator == (const Iterator& it, const Iterator& jt) - { - if(it.m_pData->type != jt.m_pData->type) - return false; - - if(it.m_pData->type == IterPriv::IT_SEQ) - return it.m_pData->seqIter == jt.m_pData->seqIter; - else if(it.m_pData->type == IterPriv::IT_MAP) - return it.m_pData->mapIter == jt.m_pData->mapIter; - - return true; - } - - bool operator != (const Iterator& it, const Iterator& jt) - { - return !(it == jt); - } -} +#include "crt.h" +#include "node.h" +#include "exceptions.h" +#include "iterpriv.h" + +namespace YAML +{ + Iterator::Iterator(): m_pData(0) + { + m_pData = new IterPriv; + } + + Iterator::Iterator(IterPriv *pData): m_pData(pData) + { + } + + Iterator::Iterator(const Iterator& rhs): m_pData(0) + { + m_pData = new IterPriv(*rhs.m_pData); + } + + Iterator& Iterator::operator = (const Iterator& rhs) + { + if(this == &rhs) + return *this; + + delete m_pData; + m_pData = new IterPriv(*rhs.m_pData); + return *this; + } + + Iterator::~Iterator() + { + delete m_pData; + } + + Iterator& Iterator::operator ++ () + { + if(m_pData->type == IterPriv::IT_SEQ) + ++m_pData->seqIter; + else if(m_pData->type == IterPriv::IT_MAP) + ++m_pData->mapIter; + + return *this; + } + + Iterator Iterator::operator ++ (int) + { + Iterator temp = *this; + + if(m_pData->type == IterPriv::IT_SEQ) + ++m_pData->seqIter; + else if(m_pData->type == IterPriv::IT_MAP) + ++m_pData->mapIter; + + return temp; + } + + const Node& Iterator::operator * () const + { + if(m_pData->type == IterPriv::IT_SEQ) + return **m_pData->seqIter; + + throw BadDereference(); + } + + const Node *Iterator::operator -> () const + { + if(m_pData->type == IterPriv::IT_SEQ) + return *m_pData->seqIter; + + throw BadDereference(); + } + + const Node& Iterator::first() const + { + if(m_pData->type == IterPriv::IT_MAP) + return *m_pData->mapIter->first; + + throw BadDereference(); + } + + const Node& Iterator::second() const + { + if(m_pData->type == IterPriv::IT_MAP) + return *m_pData->mapIter->second; + + throw BadDereference(); + } + + bool operator == (const Iterator& it, const Iterator& jt) + { + if(it.m_pData->type != jt.m_pData->type) + return false; + + if(it.m_pData->type == IterPriv::IT_SEQ) + return it.m_pData->seqIter == jt.m_pData->seqIter; + else if(it.m_pData->type == IterPriv::IT_MAP) + return it.m_pData->mapIter == jt.m_pData->mapIter; + + return true; + } + + bool operator != (const Iterator& it, const Iterator& jt) + { + return !(it == jt); + } +} diff --git a/src/iterpriv.h b/src/iterpriv.h index 5c29366..ec38617 100644 --- a/src/iterpriv.h +++ b/src/iterpriv.h @@ -1,25 +1,25 @@ -#pragma once - -#include "ltnode.h" -#include -#include - -namespace YAML -{ - class Node; - - // IterPriv - // . The implementation for iterators - essentially a union of sequence and map iterators. - struct IterPriv - { - IterPriv(): type(IT_NONE) {} - IterPriv(std::vector ::const_iterator it): type(IT_SEQ), seqIter(it) {} - IterPriv(std::map ::const_iterator it): type(IT_MAP), mapIter(it) {} - - enum ITER_TYPE { IT_NONE, IT_SEQ, IT_MAP }; - ITER_TYPE type; - - std::vector ::const_iterator seqIter; - std::map ::const_iterator mapIter; - }; -} +#pragma once + +#include "ltnode.h" +#include +#include + +namespace YAML +{ + class Node; + + // IterPriv + // . The implementation for iterators - essentially a union of sequence and map iterators. + struct IterPriv + { + IterPriv(): type(IT_NONE) {} + IterPriv(std::vector ::const_iterator it): type(IT_SEQ), seqIter(it) {} + IterPriv(std::map ::const_iterator it): type(IT_MAP), mapIter(it) {} + + enum ITER_TYPE { IT_NONE, IT_SEQ, IT_MAP }; + ITER_TYPE type; + + std::vector ::const_iterator seqIter; + std::map ::const_iterator mapIter; + }; +} diff --git a/src/ltnode.h b/src/ltnode.h index af8c1bb..958d0ac 100644 --- a/src/ltnode.h +++ b/src/ltnode.h @@ -1,10 +1,10 @@ -#pragma once - -namespace YAML -{ - class Node; - - struct ltnode { - bool operator()(const Node *pNode1, const Node *pNode2) const; - }; -} +#pragma once + +namespace YAML +{ + class Node; + + struct ltnode { + bool operator()(const Node *pNode1, const Node *pNode2) const; + }; +} diff --git a/src/map.cpp b/src/map.cpp index 727726b..facb537 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1,196 +1,196 @@ -#include "crt.h" -#include "map.h" -#include "node.h" -#include "scanner.h" -#include "token.h" -#include "exceptions.h" -#include - -namespace YAML -{ - Map::Map() - { - } - - Map::~Map() - { - Clear(); - } - - void Map::Clear() - { - for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) { - delete it->first; - delete it->second; - } - m_data.clear(); - } - - bool Map::GetBegin(std::map ::const_iterator& it) const - { - it = m_data.begin(); - return true; - } - - bool Map::GetEnd(std::map ::const_iterator& it) const - { - it = m_data.end(); - return true; - } - - void Map::Parse(Scanner *pScanner, const ParserState& state) - { - Clear(); - - // split based on start token - switch(pScanner->peek().type) { - case TT_BLOCK_MAP_START: ParseBlock(pScanner, state); break; - case TT_FLOW_MAP_START: ParseFlow(pScanner, state); break; - } - } - - void Map::ParseBlock(Scanner *pScanner, const ParserState& state) - { - // eat start token - pScanner->pop(); - - while(1) { - if(pScanner->empty()) - throw ParserException(-1, -1, ErrorMsg::END_OF_MAP); - - Token token = pScanner->peek(); - if(token.type != TT_KEY && token.type != TT_BLOCK_END) - throw ParserException(token.line, token.column, ErrorMsg::END_OF_MAP); - - pScanner->pop(); - if(token.type == TT_BLOCK_END) - break; - - Node *pKey = new Node; - Node *pValue = new Node; - - try { - // grab key - pKey->Parse(pScanner, state); - - // now grab value (optional) - if(!pScanner->empty() && pScanner->peek().type == TT_VALUE) { - pScanner->pop(); - pValue->Parse(pScanner, state); - } - - m_data[pKey] = pValue; - } catch(Exception& e) { - delete pKey; - delete pValue; - throw e; - } - } - } - - void Map::ParseFlow(Scanner *pScanner, const ParserState& state) - { - // eat start token - pScanner->pop(); - - while(1) { - if(pScanner->empty()) - throw ParserException(-1, -1, ErrorMsg::END_OF_MAP_FLOW); - - Token& token = pScanner->peek(); - // first check for end - if(token.type == TT_FLOW_MAP_END) { - pScanner->pop(); - break; - } - - // now it better be a key - if(token.type != TT_KEY) - throw ParserException(token.line, token.column, ErrorMsg::END_OF_MAP_FLOW); - - pScanner->pop(); - - Node *pKey = new Node; - Node *pValue = new Node; - - try { - // grab key - pKey->Parse(pScanner, state); - - // now grab value (optional) - if(!pScanner->empty() && pScanner->peek().type == TT_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 == TT_FLOW_ENTRY) - pScanner->pop(); - else if(nextToken.type != TT_FLOW_MAP_END) - throw ParserException(nextToken.line, nextToken.column, ErrorMsg::END_OF_MAP_FLOW); - - m_data[pKey] = pValue; - } catch(Exception& e) { - // clean up and rethrow - delete pKey; - delete pValue; - throw e; - } - } - } - - void Map::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) - { - if(startedLine && !onlyOneCharOnLine) - out << "\n"; - - for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) { - if((startedLine && !onlyOneCharOnLine) || it != m_data.begin()) { - for(int i=0;ifirst->Write(out, indent + 1, true, it!= m_data.begin() || !startedLine || onlyOneCharOnLine); - - for(int i=0;isecond->Write(out, indent + 1, true, true); - } - - if(m_data.empty()) - out << "\n"; - } - - int Map::Compare(Content *pContent) - { - return -pContent->Compare(this); - } - - int Map::Compare(Map *pMap) - { - node_map::const_iterator it = m_data.begin(), jt = pMap->m_data.begin(); - while(1) { - if(it == m_data.end()) { - if(jt == pMap->m_data.end()) - return 0; - else - return -1; - } - if(jt == pMap->m_data.end()) - return 1; - - int cmp = it->first->Compare(*jt->first); - if(cmp != 0) - return cmp; - - cmp = it->second->Compare(*jt->second); - if(cmp != 0) - return cmp; - } - - return 0; - } -} +#include "crt.h" +#include "map.h" +#include "node.h" +#include "scanner.h" +#include "token.h" +#include "exceptions.h" +#include + +namespace YAML +{ + Map::Map() + { + } + + Map::~Map() + { + Clear(); + } + + void Map::Clear() + { + for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) { + delete it->first; + delete it->second; + } + m_data.clear(); + } + + bool Map::GetBegin(std::map ::const_iterator& it) const + { + it = m_data.begin(); + return true; + } + + bool Map::GetEnd(std::map ::const_iterator& it) const + { + it = m_data.end(); + return true; + } + + void Map::Parse(Scanner *pScanner, const ParserState& state) + { + Clear(); + + // split based on start token + switch(pScanner->peek().type) { + case TT_BLOCK_MAP_START: ParseBlock(pScanner, state); break; + case TT_FLOW_MAP_START: ParseFlow(pScanner, state); break; + } + } + + void Map::ParseBlock(Scanner *pScanner, const ParserState& state) + { + // eat start token + pScanner->pop(); + + while(1) { + if(pScanner->empty()) + throw ParserException(-1, -1, ErrorMsg::END_OF_MAP); + + Token token = pScanner->peek(); + if(token.type != TT_KEY && token.type != TT_BLOCK_END) + throw ParserException(token.line, token.column, ErrorMsg::END_OF_MAP); + + pScanner->pop(); + if(token.type == TT_BLOCK_END) + break; + + Node *pKey = new Node; + Node *pValue = new Node; + + try { + // grab key + pKey->Parse(pScanner, state); + + // now grab value (optional) + if(!pScanner->empty() && pScanner->peek().type == TT_VALUE) { + pScanner->pop(); + pValue->Parse(pScanner, state); + } + + m_data[pKey] = pValue; + } catch(Exception& e) { + delete pKey; + delete pValue; + throw e; + } + } + } + + void Map::ParseFlow(Scanner *pScanner, const ParserState& state) + { + // eat start token + pScanner->pop(); + + while(1) { + if(pScanner->empty()) + throw ParserException(-1, -1, ErrorMsg::END_OF_MAP_FLOW); + + Token& token = pScanner->peek(); + // first check for end + if(token.type == TT_FLOW_MAP_END) { + pScanner->pop(); + break; + } + + // now it better be a key + if(token.type != TT_KEY) + throw ParserException(token.line, token.column, ErrorMsg::END_OF_MAP_FLOW); + + pScanner->pop(); + + Node *pKey = new Node; + Node *pValue = new Node; + + try { + // grab key + pKey->Parse(pScanner, state); + + // now grab value (optional) + if(!pScanner->empty() && pScanner->peek().type == TT_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 == TT_FLOW_ENTRY) + pScanner->pop(); + else if(nextToken.type != TT_FLOW_MAP_END) + throw ParserException(nextToken.line, nextToken.column, ErrorMsg::END_OF_MAP_FLOW); + + m_data[pKey] = pValue; + } catch(Exception& e) { + // clean up and rethrow + delete pKey; + delete pValue; + throw e; + } + } + } + + void Map::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) + { + if(startedLine && !onlyOneCharOnLine) + out << "\n"; + + for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) { + if((startedLine && !onlyOneCharOnLine) || it != m_data.begin()) { + for(int i=0;ifirst->Write(out, indent + 1, true, it!= m_data.begin() || !startedLine || onlyOneCharOnLine); + + for(int i=0;isecond->Write(out, indent + 1, true, true); + } + + if(m_data.empty()) + out << "\n"; + } + + int Map::Compare(Content *pContent) + { + return -pContent->Compare(this); + } + + int Map::Compare(Map *pMap) + { + node_map::const_iterator it = m_data.begin(), jt = pMap->m_data.begin(); + while(1) { + if(it == m_data.end()) { + if(jt == pMap->m_data.end()) + return 0; + else + return -1; + } + if(jt == pMap->m_data.end()) + return 1; + + int cmp = it->first->Compare(*jt->first); + if(cmp != 0) + return cmp; + + cmp = it->second->Compare(*jt->second); + if(cmp != 0) + return cmp; + } + + return 0; + } +} diff --git a/src/map.h b/src/map.h index 8e58887..0f7c3bf 100644 --- a/src/map.h +++ b/src/map.h @@ -1,38 +1,38 @@ -#pragma once - -#include "content.h" -#include - -namespace YAML -{ - class Node; - - class Map: public Content - { - public: - Map(); - virtual ~Map(); - - void Clear(); - virtual bool GetBegin(std::map ::const_iterator& it) const; - virtual bool GetEnd(std::map ::const_iterator& it) const; - virtual void Parse(Scanner *pScanner, const ParserState& state); - virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); - - virtual bool IsMap() const { return true; } - - // ordering - virtual int Compare(Content *pContent); - virtual int Compare(Scalar *pScalar) { return 1; } - virtual int Compare(Sequence *pSeq) { return 1; } - virtual int Compare(Map *pMap); - - private: - void ParseBlock(Scanner *pScanner, const ParserState& state); - void ParseFlow(Scanner *pScanner, const ParserState& state); - - protected: - typedef std::map node_map; - node_map m_data; - }; -} +#pragma once + +#include "content.h" +#include + +namespace YAML +{ + class Node; + + class Map: public Content + { + public: + Map(); + virtual ~Map(); + + void Clear(); + virtual bool GetBegin(std::map ::const_iterator& it) const; + virtual bool GetEnd(std::map ::const_iterator& it) const; + virtual void Parse(Scanner *pScanner, const ParserState& state); + virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); + + virtual bool IsMap() const { return true; } + + // ordering + virtual int Compare(Content *pContent); + virtual int Compare(Scalar *pScalar) { return 1; } + virtual int Compare(Sequence *pSeq) { return 1; } + virtual int Compare(Map *pMap); + + private: + void ParseBlock(Scanner *pScanner, const ParserState& state); + void ParseFlow(Scanner *pScanner, const ParserState& state); + + protected: + typedef std::map node_map; + node_map m_data; + }; +} diff --git a/src/node.cpp b/src/node.cpp index 64ec8b3..f009903 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -1,317 +1,317 @@ -#include "crt.h" -#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 "iterpriv.h" - -namespace YAML -{ - // the ordering! - bool ltnode::operator ()(const Node *pNode1, const Node *pNode2) const - { - return *pNode1 < *pNode2; - } - - Node::Node(): m_pContent(0), m_alias(false) - { - } - - Node::~Node() - { - Clear(); - } - - void Node::Clear() - { - delete m_pContent; - m_pContent = 0; - m_alias = false; - } - - void Node::Parse(Scanner *pScanner, const ParserState& state) - { - Clear(); - - ParseHeader(pScanner, state); - - // is this an alias? if so, it can have no content - if(m_alias) - return; - - // now split based on what kind of node we should be - switch(pScanner->peek().type) { - case TT_SCALAR: - m_pContent = new Scalar; - m_pContent->Parse(pScanner, state); - break; - case TT_FLOW_SEQ_START: - case TT_BLOCK_SEQ_START: - case TT_BLOCK_ENTRY: - m_pContent = new Sequence; - m_pContent->Parse(pScanner, state); - break; - case TT_FLOW_MAP_START: - case TT_BLOCK_MAP_START: - m_pContent = new Map; - m_pContent->Parse(pScanner, state); - break; - } - } - - // ParseHeader - // . Grabs any tag, alias, or anchor tokens and deals with them. - void Node::ParseHeader(Scanner *pScanner, const ParserState& state) - { - while(1) { - if(pScanner->empty()) - return; - - switch(pScanner->peek().type) { - case TT_TAG: ParseTag(pScanner, state); break; - case TT_ANCHOR: ParseAnchor(pScanner, state); break; - case TT_ALIAS: ParseAlias(pScanner, state); break; - default: return; - } - } - } - - void Node::ParseTag(Scanner *pScanner, const ParserState& state) - { - Token& token = pScanner->peek(); - if(m_tag != "") - throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_TAGS); - - m_tag = state.TranslateTag(token.value); - - for(unsigned i=0;ipop(); - } - - void Node::ParseAnchor(Scanner *pScanner, const ParserState& state) - { - Token& token = pScanner->peek(); - if(m_anchor != "") - throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ANCHORS); - - m_anchor = token.value; - m_alias = false; - pScanner->pop(); - } - - void Node::ParseAlias(Scanner *pScanner, const ParserState& state) - { - Token& token = pScanner->peek(); - if(m_anchor != "") - throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ALIASES); - if(m_tag != "") - throw ParserException(token.line, token.column, ErrorMsg::ALIAS_CONTENT); - - m_anchor = token.value; - m_alias = true; - pScanner->pop(); - } - - void Node::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const - { - // write anchor/alias - if(m_anchor != "") { - if(m_alias) - out << std::string("*"); - else - out << std::string("&"); - out << m_anchor << std::string(" "); - startedLine = true; - onlyOneCharOnLine = false; - } - - // write tag - if(m_tag != "") { - out << std::string("!<") << m_tag << std::string("> "); - startedLine = true; - onlyOneCharOnLine = false; - } - - if(!m_pContent) { - out << std::string("\n"); - } else { - m_pContent->Write(out, indent, startedLine, onlyOneCharOnLine); - } - } - - CONTENT_TYPE Node::GetType() const - { - if(!m_pContent) - return CT_NONE; - - 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 - // Returns an iterator to the beginning of this (sequence or map). - Iterator Node::begin() const - { - if(!m_pContent) - return Iterator(); - - std::vector ::const_iterator seqIter; - if(m_pContent->GetBegin(seqIter)) - return Iterator(new IterPriv(seqIter)); - - std::map ::const_iterator mapIter; - if(m_pContent->GetBegin(mapIter)) - return Iterator(new IterPriv(mapIter)); - - return Iterator(); - } - - // end - // . Returns an iterator to the end of this (sequence or map). - Iterator Node::end() const - { - if(!m_pContent) - return Iterator(); - - std::vector ::const_iterator seqIter; - if(m_pContent->GetEnd(seqIter)) - return Iterator(new IterPriv(seqIter)); - - std::map ::const_iterator mapIter; - if(m_pContent->GetEnd(mapIter)) - return Iterator(new IterPriv(mapIter)); - - return Iterator(); - } - - // size - // . Returns the size of this node, if it's a sequence node. - // . Otherwise, returns zero. - unsigned Node::size() const - { - if(!m_pContent) - return 0; - - return m_pContent->GetSize(); - } - - const Node& Node::operator [] (unsigned u) const - { - if(!m_pContent) - throw BadDereference(); - - Node *pNode = m_pContent->GetNode(u); - if(pNode) - return *pNode; - - return GetValue(u); - } - - const Node& Node::operator [] (int i) const - { - if(!m_pContent) - throw BadDereference(); - - Node *pNode = m_pContent->GetNode(i); - if(pNode) - return *pNode; - - return GetValue(i); - } - - /////////////////////////////////////////////////////// - // Extraction - - void operator >> (const Node& node, std::string& s) - { - if(!node.m_pContent) - throw; - - node.m_pContent->Read(s); - } - - void operator >> (const Node& node, int& i) - { - if(!node.m_pContent) - throw; - - node.m_pContent->Read(i); - } - - void operator >> (const Node& node, unsigned& u) - { - if(!node.m_pContent) - throw; - - node.m_pContent->Read(u); - } - - void operator >> (const Node& node, long& l) - { - if(!node.m_pContent) - throw; - - node.m_pContent->Read(l); - } - - void operator >> (const Node& node, float& f) - { - if(!node.m_pContent) - throw; - - node.m_pContent->Read(f); - } - - void operator >> (const Node& node, double& d) - { - if(!node.m_pContent) - throw; - - node.m_pContent->Read(d); - } - - void operator >> (const Node& node, char& c) - { - if(!node.m_pContent) - throw; - - node.m_pContent->Read(c); - } - - std::ostream& operator << (std::ostream& out, const Node& node) - { - node.Write(out, 0, false, false); - return out; - } - - int Node::Compare(const Node& rhs) const - { - // Step 1: no content is the smallest - if(!m_pContent) { - if(rhs.m_pContent) - return -1; - else - return 0; - } - if(!rhs.m_pContent) - return 1; - - return m_pContent->Compare(rhs.m_pContent); - } - - bool operator < (const Node& n1, const Node& n2) - { - return n1.Compare(n2) < 0; - } -} +#include "crt.h" +#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 "iterpriv.h" + +namespace YAML +{ + // the ordering! + bool ltnode::operator ()(const Node *pNode1, const Node *pNode2) const + { + return *pNode1 < *pNode2; + } + + Node::Node(): m_pContent(0), m_alias(false) + { + } + + Node::~Node() + { + Clear(); + } + + void Node::Clear() + { + delete m_pContent; + m_pContent = 0; + m_alias = false; + } + + void Node::Parse(Scanner *pScanner, const ParserState& state) + { + Clear(); + + ParseHeader(pScanner, state); + + // is this an alias? if so, it can have no content + if(m_alias) + return; + + // now split based on what kind of node we should be + switch(pScanner->peek().type) { + case TT_SCALAR: + m_pContent = new Scalar; + m_pContent->Parse(pScanner, state); + break; + case TT_FLOW_SEQ_START: + case TT_BLOCK_SEQ_START: + case TT_BLOCK_ENTRY: + m_pContent = new Sequence; + m_pContent->Parse(pScanner, state); + break; + case TT_FLOW_MAP_START: + case TT_BLOCK_MAP_START: + m_pContent = new Map; + m_pContent->Parse(pScanner, state); + break; + } + } + + // ParseHeader + // . Grabs any tag, alias, or anchor tokens and deals with them. + void Node::ParseHeader(Scanner *pScanner, const ParserState& state) + { + while(1) { + if(pScanner->empty()) + return; + + switch(pScanner->peek().type) { + case TT_TAG: ParseTag(pScanner, state); break; + case TT_ANCHOR: ParseAnchor(pScanner, state); break; + case TT_ALIAS: ParseAlias(pScanner, state); break; + default: return; + } + } + } + + void Node::ParseTag(Scanner *pScanner, const ParserState& state) + { + Token& token = pScanner->peek(); + if(m_tag != "") + throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_TAGS); + + m_tag = state.TranslateTag(token.value); + + for(unsigned i=0;ipop(); + } + + void Node::ParseAnchor(Scanner *pScanner, const ParserState& state) + { + Token& token = pScanner->peek(); + if(m_anchor != "") + throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ANCHORS); + + m_anchor = token.value; + m_alias = false; + pScanner->pop(); + } + + void Node::ParseAlias(Scanner *pScanner, const ParserState& state) + { + Token& token = pScanner->peek(); + if(m_anchor != "") + throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ALIASES); + if(m_tag != "") + throw ParserException(token.line, token.column, ErrorMsg::ALIAS_CONTENT); + + m_anchor = token.value; + m_alias = true; + pScanner->pop(); + } + + void Node::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const + { + // write anchor/alias + if(m_anchor != "") { + if(m_alias) + out << std::string("*"); + else + out << std::string("&"); + out << m_anchor << std::string(" "); + startedLine = true; + onlyOneCharOnLine = false; + } + + // write tag + if(m_tag != "") { + out << std::string("!<") << m_tag << std::string("> "); + startedLine = true; + onlyOneCharOnLine = false; + } + + if(!m_pContent) { + out << std::string("\n"); + } else { + m_pContent->Write(out, indent, startedLine, onlyOneCharOnLine); + } + } + + CONTENT_TYPE Node::GetType() const + { + if(!m_pContent) + return CT_NONE; + + 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 + // Returns an iterator to the beginning of this (sequence or map). + Iterator Node::begin() const + { + if(!m_pContent) + return Iterator(); + + std::vector ::const_iterator seqIter; + if(m_pContent->GetBegin(seqIter)) + return Iterator(new IterPriv(seqIter)); + + std::map ::const_iterator mapIter; + if(m_pContent->GetBegin(mapIter)) + return Iterator(new IterPriv(mapIter)); + + return Iterator(); + } + + // end + // . Returns an iterator to the end of this (sequence or map). + Iterator Node::end() const + { + if(!m_pContent) + return Iterator(); + + std::vector ::const_iterator seqIter; + if(m_pContent->GetEnd(seqIter)) + return Iterator(new IterPriv(seqIter)); + + std::map ::const_iterator mapIter; + if(m_pContent->GetEnd(mapIter)) + return Iterator(new IterPriv(mapIter)); + + return Iterator(); + } + + // size + // . Returns the size of this node, if it's a sequence node. + // . Otherwise, returns zero. + unsigned Node::size() const + { + if(!m_pContent) + return 0; + + return m_pContent->GetSize(); + } + + const Node& Node::operator [] (unsigned u) const + { + if(!m_pContent) + throw BadDereference(); + + Node *pNode = m_pContent->GetNode(u); + if(pNode) + return *pNode; + + return GetValue(u); + } + + const Node& Node::operator [] (int i) const + { + if(!m_pContent) + throw BadDereference(); + + Node *pNode = m_pContent->GetNode(i); + if(pNode) + return *pNode; + + return GetValue(i); + } + + /////////////////////////////////////////////////////// + // Extraction + + void operator >> (const Node& node, std::string& s) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(s); + } + + void operator >> (const Node& node, int& i) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(i); + } + + void operator >> (const Node& node, unsigned& u) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(u); + } + + void operator >> (const Node& node, long& l) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(l); + } + + void operator >> (const Node& node, float& f) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(f); + } + + void operator >> (const Node& node, double& d) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(d); + } + + void operator >> (const Node& node, char& c) + { + if(!node.m_pContent) + throw; + + node.m_pContent->Read(c); + } + + std::ostream& operator << (std::ostream& out, const Node& node) + { + node.Write(out, 0, false, false); + return out; + } + + int Node::Compare(const Node& rhs) const + { + // Step 1: no content is the smallest + if(!m_pContent) { + if(rhs.m_pContent) + return -1; + else + return 0; + } + if(!rhs.m_pContent) + return 1; + + return m_pContent->Compare(rhs.m_pContent); + } + + bool operator < (const Node& n1, const Node& n2) + { + return n1.Compare(n2) < 0; + } +} diff --git a/src/parser.cpp b/src/parser.cpp index 18c7c8d..d0ba2b2 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,133 +1,133 @@ -#include "crt.h" -#include "parser.h" -#include "scanner.h" -#include "token.h" -#include "exceptions.h" -#include - -namespace YAML -{ - Parser::Parser(std::istream& in): m_pScanner(0) - { - Load(in); - } - - Parser::~Parser() - { - delete m_pScanner; - } - - Parser::operator bool() const - { - return !m_pScanner->empty(); - } - - void Parser::Load(std::istream& in) - { - delete m_pScanner; - m_pScanner = new Scanner(in); - m_state.Reset(); - } - - // GetNextDocument - // . Reads the next document in the queue (of tokens). - // . Throws a ParserException on error. - void Parser::GetNextDocument(Node& document) - { - // clear node - document.Clear(); - - // first read directives - ParseDirectives(); - - // we better have some tokens in the queue - if(m_pScanner->empty()) - return; - - // first eat doc start (optional) - if(m_pScanner->peek().type == TT_DOC_START) - m_pScanner->pop(); - - // now parse our root node - document.Parse(m_pScanner, m_state); - - // and finally eat any doc ends we see - while(!m_pScanner->empty() && m_pScanner->peek().type == TT_DOC_END) - m_pScanner->pop(); - } - - // ParseDirectives - // . Reads any directives that are next in the queue. - void Parser::ParseDirectives() - { - bool readDirective = false; - - while(1) { - if(m_pScanner->empty()) - break; - - Token& token = m_pScanner->peek(); - if(token.type != TT_DIRECTIVE) - break; - - // 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_state.Reset(); - - readDirective = true; - HandleDirective(&token); - m_pScanner->pop(); - } - } - - void Parser::HandleDirective(Token *pToken) - { - if(pToken->value == "YAML") - HandleYamlDirective(pToken); - else if(pToken->value == "TAG") - HandleTagDirective(pToken); - } - - // HandleYamlDirective - // . Should be of the form 'major.minor' (like a version number) - void Parser::HandleYamlDirective(Token *pToken) - { - if(pToken->params.size() != 1) - throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_DIRECTIVE_ARGS); - - std::stringstream str(pToken->params[0]); - str >> m_state.version.major; - str.get(); - str >> m_state.version.minor; - if(!str || str.peek() != EOF) - throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_VERSION + pToken->params[0]); - - if(m_state.version.major > 1) - throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_MAJOR_VERSION); - - // TODO: warning on major == 1, minor > 2? - } - - // HandleTagDirective - // . Should be of the form 'handle prefix', where 'handle' is converted to 'prefix' in the file. - void Parser::HandleTagDirective(Token *pToken) - { - if(pToken->params.size() != 2) - throw ParserException(pToken->line, pToken->column, ErrorMsg::TAG_DIRECTIVE_ARGS); - - std::string handle = pToken->params[0], prefix = pToken->params[1]; - m_state.tags[handle] = prefix; - } - - void Parser::PrintTokens(std::ostream& out) - { - while(1) { - if(m_pScanner->empty()) - break; - - out << m_pScanner->peek() << "\n"; - m_pScanner->pop(); - } - } -} +#include "crt.h" +#include "parser.h" +#include "scanner.h" +#include "token.h" +#include "exceptions.h" +#include + +namespace YAML +{ + Parser::Parser(std::istream& in): m_pScanner(0) + { + Load(in); + } + + Parser::~Parser() + { + delete m_pScanner; + } + + Parser::operator bool() const + { + return !m_pScanner->empty(); + } + + void Parser::Load(std::istream& in) + { + delete m_pScanner; + m_pScanner = new Scanner(in); + m_state.Reset(); + } + + // GetNextDocument + // . Reads the next document in the queue (of tokens). + // . Throws a ParserException on error. + void Parser::GetNextDocument(Node& document) + { + // clear node + document.Clear(); + + // first read directives + ParseDirectives(); + + // we better have some tokens in the queue + if(m_pScanner->empty()) + return; + + // first eat doc start (optional) + if(m_pScanner->peek().type == TT_DOC_START) + m_pScanner->pop(); + + // now parse our root node + document.Parse(m_pScanner, m_state); + + // and finally eat any doc ends we see + while(!m_pScanner->empty() && m_pScanner->peek().type == TT_DOC_END) + m_pScanner->pop(); + } + + // ParseDirectives + // . Reads any directives that are next in the queue. + void Parser::ParseDirectives() + { + bool readDirective = false; + + while(1) { + if(m_pScanner->empty()) + break; + + Token& token = m_pScanner->peek(); + if(token.type != TT_DIRECTIVE) + break; + + // 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_state.Reset(); + + readDirective = true; + HandleDirective(&token); + m_pScanner->pop(); + } + } + + void Parser::HandleDirective(Token *pToken) + { + if(pToken->value == "YAML") + HandleYamlDirective(pToken); + else if(pToken->value == "TAG") + HandleTagDirective(pToken); + } + + // HandleYamlDirective + // . Should be of the form 'major.minor' (like a version number) + void Parser::HandleYamlDirective(Token *pToken) + { + if(pToken->params.size() != 1) + throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_DIRECTIVE_ARGS); + + std::stringstream str(pToken->params[0]); + str >> m_state.version.major; + str.get(); + str >> m_state.version.minor; + if(!str || str.peek() != EOF) + throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_VERSION + pToken->params[0]); + + if(m_state.version.major > 1) + throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_MAJOR_VERSION); + + // TODO: warning on major == 1, minor > 2? + } + + // HandleTagDirective + // . Should be of the form 'handle prefix', where 'handle' is converted to 'prefix' in the file. + void Parser::HandleTagDirective(Token *pToken) + { + if(pToken->params.size() != 2) + throw ParserException(pToken->line, pToken->column, ErrorMsg::TAG_DIRECTIVE_ARGS); + + std::string handle = pToken->params[0], prefix = pToken->params[1]; + m_state.tags[handle] = prefix; + } + + void Parser::PrintTokens(std::ostream& out) + { + while(1) { + if(m_pScanner->empty()) + break; + + out << m_pScanner->peek() << "\n"; + m_pScanner->pop(); + } + } +} diff --git a/src/parserstate.cpp b/src/parserstate.cpp index 4a14b3a..40adb03 100644 --- a/src/parserstate.cpp +++ b/src/parserstate.cpp @@ -1,26 +1,26 @@ -#include "crt.h" -#include "parserstate.h" - -namespace YAML -{ - void ParserState::Reset() - { - // version - version.major = 1; - version.minor = 2; - - // and tags - tags.clear(); - tags["!"] = "!"; - tags["!!"] = "tag:yaml.org,2002:"; - } - - std::string ParserState::TranslateTag(const std::string& handle) const - { - std::map ::const_iterator it = tags.find(handle); - if(it == tags.end()) - return handle; - - return it->second; - } -} +#include "crt.h" +#include "parserstate.h" + +namespace YAML +{ + void ParserState::Reset() + { + // version + version.major = 1; + version.minor = 2; + + // and tags + tags.clear(); + tags["!"] = "!"; + tags["!!"] = "tag:yaml.org,2002:"; + } + + std::string ParserState::TranslateTag(const std::string& handle) const + { + std::map ::const_iterator it = tags.find(handle); + if(it == tags.end()) + return handle; + + return it->second; + } +} diff --git a/src/regex.cpp b/src/regex.cpp index c40a087..9c0e217 100644 --- a/src/regex.cpp +++ b/src/regex.cpp @@ -1,306 +1,306 @@ -#include "crt.h" -#include "regex.h" -#include "stream.h" -#include - -namespace YAML -{ - RegEx::RegEx(REGEX_OP op): m_op(op), m_pOp(0) - { - SetOp(); - } - - RegEx::RegEx(const RegEx& rhs): m_pOp(0) - { - m_op = rhs.m_op; - m_a = rhs.m_a; - m_z = rhs.m_z; - m_params = rhs.m_params; - - SetOp(); - } - - RegEx::RegEx(): m_op(REGEX_EMPTY), m_pOp(0) - { - SetOp(); - } - - RegEx::RegEx(char ch): m_op(REGEX_MATCH), m_pOp(0), m_a(ch) - { - SetOp(); - } - - RegEx::RegEx(char a, char z): m_op(REGEX_RANGE), m_pOp(0), m_a(a), m_z(z) - { - SetOp(); - } - - RegEx::RegEx(const std::string& str, REGEX_OP op): m_op(op), m_pOp(0) - { - for(unsigned i=0;i= 0; - } - - bool RegEx::Matches(std::istream& in) const - { - return Match(in) >= 0; - } - - bool RegEx::Matches(Stream& in) const - { - return Match(in) >= 0; - } - - // Match - // . Matches the given string against this regular expression. - // . Returns the number of characters matched. - // . Returns -1 if no characters were matched (the reason for - // not returning zero is that we may have an empty regex - // which is ALWAYS successful at matching zero characters). - int RegEx::Match(const std::string& str) const - { - if(!m_pOp) - return 0; - - return m_pOp->Match(str, *this); - } - - // Match - int RegEx::Match(Stream& in) const - { - return Match(in.stream()); - } - - // Match - // . The stream version does the same thing as the string version; - // REMEMBER that we only match from the start of the stream! - // . Note: the istream is not a const reference, but we guarantee - // that the pointer will be in the same spot, and we'll clear its - // flags before we end. - int RegEx::Match(std::istream& in) const - { - if(!m_pOp) - return -1; - - int pos = in.tellg(); - int ret = m_pOp->Match(in, *this); - - // reset input stream! - in.clear(); - in.seekg(pos); - - return ret; - } - - RegEx operator ! (const RegEx& ex) - { - RegEx ret(REGEX_NOT); - ret.m_params.push_back(ex); - return ret; - } - - RegEx operator || (const RegEx& ex1, const RegEx& ex2) - { - RegEx ret(REGEX_OR); - ret.m_params.push_back(ex1); - ret.m_params.push_back(ex2); - return ret; - } - - RegEx operator && (const RegEx& ex1, const RegEx& ex2) - { - RegEx ret(REGEX_AND); - ret.m_params.push_back(ex1); - ret.m_params.push_back(ex2); - return ret; - } - - RegEx operator + (const RegEx& ex1, const RegEx& ex2) - { - RegEx ret(REGEX_SEQ); - ret.m_params.push_back(ex1); - ret.m_params.push_back(ex2); - return ret; - } - - ////////////////////////////////////////////////////////////////////////////// - // Operators - - // MatchOperator - int RegEx::MatchOperator::Match(const std::string& str, const RegEx& regex) const - { - if(str.empty() || str[0] != regex.m_a) - return -1; - return 1; - } - - - int RegEx::MatchOperator::Match(std::istream& in, const RegEx& regex) const - { - if(!in || in.peek() != regex.m_a) - return -1; - return 1; - } - - // RangeOperator - int RegEx::RangeOperator::Match(const std::string& str, const RegEx& regex) const - { - if(str.empty() || regex.m_a > str[0] || regex.m_z < str[0]) - return -1; - return 1; - } - - int RegEx::RangeOperator::Match(std::istream& in, const RegEx& regex) const - { - if(!in || regex.m_a > in.peek() || regex.m_z < in.peek()) - return -1; - return 1; - } - - // OrOperator - int RegEx::OrOperator::Match(const std::string& str, const RegEx& regex) const - { - for(unsigned i=0;i= 0) - return n; - } - return -1; - } - - int RegEx::OrOperator::Match(std::istream& in, const RegEx& regex) const - { - for(unsigned i=0;i= 0) - return n; - } - return -1; - } - - // AndOperator - // Note: 'AND' is a little funny, since we may be required to match things - // of different lengths. If we find a match, we return the length of - // the FIRST entry on the list. - int RegEx::AndOperator::Match(const std::string& str, const RegEx& regex) const - { - int first = -1; - for(unsigned i=0;i= 0) - return -1; - return 1; - } - - int RegEx::NotOperator::Match(std::istream& in, const RegEx& regex) const - { - if(regex.m_params.empty()) - return -1; - if(regex.m_params[0].Match(in) >= 0) - return -1; - return 1; - } - - // SeqOperator - int RegEx::SeqOperator::Match(const std::string& str, const RegEx& regex) const - { - int offset = 0; - for(unsigned i=0;i + +namespace YAML +{ + RegEx::RegEx(REGEX_OP op): m_op(op), m_pOp(0) + { + SetOp(); + } + + RegEx::RegEx(const RegEx& rhs): m_pOp(0) + { + m_op = rhs.m_op; + m_a = rhs.m_a; + m_z = rhs.m_z; + m_params = rhs.m_params; + + SetOp(); + } + + RegEx::RegEx(): m_op(REGEX_EMPTY), m_pOp(0) + { + SetOp(); + } + + RegEx::RegEx(char ch): m_op(REGEX_MATCH), m_pOp(0), m_a(ch) + { + SetOp(); + } + + RegEx::RegEx(char a, char z): m_op(REGEX_RANGE), m_pOp(0), m_a(a), m_z(z) + { + SetOp(); + } + + RegEx::RegEx(const std::string& str, REGEX_OP op): m_op(op), m_pOp(0) + { + for(unsigned i=0;i= 0; + } + + bool RegEx::Matches(std::istream& in) const + { + return Match(in) >= 0; + } + + bool RegEx::Matches(Stream& in) const + { + return Match(in) >= 0; + } + + // Match + // . Matches the given string against this regular expression. + // . Returns the number of characters matched. + // . Returns -1 if no characters were matched (the reason for + // not returning zero is that we may have an empty regex + // which is ALWAYS successful at matching zero characters). + int RegEx::Match(const std::string& str) const + { + if(!m_pOp) + return 0; + + return m_pOp->Match(str, *this); + } + + // Match + int RegEx::Match(Stream& in) const + { + return Match(in.stream()); + } + + // Match + // . The stream version does the same thing as the string version; + // REMEMBER that we only match from the start of the stream! + // . Note: the istream is not a const reference, but we guarantee + // that the pointer will be in the same spot, and we'll clear its + // flags before we end. + int RegEx::Match(std::istream& in) const + { + if(!m_pOp) + return -1; + + int pos = in.tellg(); + int ret = m_pOp->Match(in, *this); + + // reset input stream! + in.clear(); + in.seekg(pos); + + return ret; + } + + RegEx operator ! (const RegEx& ex) + { + RegEx ret(REGEX_NOT); + ret.m_params.push_back(ex); + return ret; + } + + RegEx operator || (const RegEx& ex1, const RegEx& ex2) + { + RegEx ret(REGEX_OR); + ret.m_params.push_back(ex1); + ret.m_params.push_back(ex2); + return ret; + } + + RegEx operator && (const RegEx& ex1, const RegEx& ex2) + { + RegEx ret(REGEX_AND); + ret.m_params.push_back(ex1); + ret.m_params.push_back(ex2); + return ret; + } + + RegEx operator + (const RegEx& ex1, const RegEx& ex2) + { + RegEx ret(REGEX_SEQ); + ret.m_params.push_back(ex1); + ret.m_params.push_back(ex2); + return ret; + } + + ////////////////////////////////////////////////////////////////////////////// + // Operators + + // MatchOperator + int RegEx::MatchOperator::Match(const std::string& str, const RegEx& regex) const + { + if(str.empty() || str[0] != regex.m_a) + return -1; + return 1; + } + + + int RegEx::MatchOperator::Match(std::istream& in, const RegEx& regex) const + { + if(!in || in.peek() != regex.m_a) + return -1; + return 1; + } + + // RangeOperator + int RegEx::RangeOperator::Match(const std::string& str, const RegEx& regex) const + { + if(str.empty() || regex.m_a > str[0] || regex.m_z < str[0]) + return -1; + return 1; + } + + int RegEx::RangeOperator::Match(std::istream& in, const RegEx& regex) const + { + if(!in || regex.m_a > in.peek() || regex.m_z < in.peek()) + return -1; + return 1; + } + + // OrOperator + int RegEx::OrOperator::Match(const std::string& str, const RegEx& regex) const + { + for(unsigned i=0;i= 0) + return n; + } + return -1; + } + + int RegEx::OrOperator::Match(std::istream& in, const RegEx& regex) const + { + for(unsigned i=0;i= 0) + return n; + } + return -1; + } + + // AndOperator + // Note: 'AND' is a little funny, since we may be required to match things + // of different lengths. If we find a match, we return the length of + // the FIRST entry on the list. + int RegEx::AndOperator::Match(const std::string& str, const RegEx& regex) const + { + int first = -1; + for(unsigned i=0;i= 0) + return -1; + return 1; + } + + int RegEx::NotOperator::Match(std::istream& in, const RegEx& regex) const + { + if(regex.m_params.empty()) + return -1; + if(regex.m_params[0].Match(in) >= 0) + return -1; + return 1; + } + + // SeqOperator + int RegEx::SeqOperator::Match(const std::string& str, const RegEx& regex) const + { + int offset = 0; + for(unsigned i=0;i -#include -#include - -namespace YAML -{ - struct Stream; - - enum REGEX_OP { REGEX_EMPTY, REGEX_MATCH, REGEX_RANGE, REGEX_OR, REGEX_AND, REGEX_NOT, REGEX_SEQ }; - - // simplified regular expressions - // . Only straightforward matches (no repeated characters) - // . Only matches from start of string - class RegEx - { - private: - struct Operator { - virtual ~Operator() {} - virtual int Match(const std::string& str, const RegEx& regex) const = 0; - virtual int Match(std::istream& in, const RegEx& regex) const = 0; - }; - - struct MatchOperator: public Operator { - virtual int Match(const std::string& str, const RegEx& regex) const; - virtual int Match(std::istream& in, const RegEx& regex) const; - }; - - struct RangeOperator: public Operator { - virtual int Match(const std::string& str, const RegEx& regex) const; - virtual int Match(std::istream& in, const RegEx& regex) const; - }; - - struct OrOperator: public Operator { - virtual int Match(const std::string& str, const RegEx& regex) const; - virtual int Match(std::istream& in, const RegEx& regex) const; - }; - - struct AndOperator: public Operator { - virtual int Match(const std::string& str, const RegEx& regex) const; - virtual int Match(std::istream& in, const RegEx& regex) const; - }; - - struct NotOperator: public Operator { - virtual int Match(const std::string& str, const RegEx& regex) const; - virtual int Match(std::istream& in, const RegEx& regex) const; - }; - - struct SeqOperator: public Operator { - virtual int Match(const std::string& str, const RegEx& regex) const; - virtual int Match(std::istream& in, const RegEx& regex) const; - }; - - public: - friend struct Operator; - - RegEx(); - RegEx(char ch); - RegEx(char a, char z); - RegEx(const std::string& str, REGEX_OP op = REGEX_SEQ); - RegEx(const RegEx& rhs); - ~RegEx(); - - RegEx& operator = (const RegEx& rhs); - - bool Matches(char ch) const; - bool Matches(const std::string& str) const; - bool Matches(std::istream& in) const; - bool Matches(Stream& in) const; - int Match(const std::string& str) const; - int Match(std::istream& in) const; - int Match(Stream& in) const; - - friend RegEx operator ! (const RegEx& ex); - friend RegEx operator || (const RegEx& ex1, const RegEx& ex2); - friend RegEx operator && (const RegEx& ex1, const RegEx& ex2); - friend RegEx operator + (const RegEx& ex1, const RegEx& ex2); - - private: - RegEx(REGEX_OP op); - void SetOp(); - - private: - REGEX_OP m_op; - Operator *m_pOp; - char m_a, m_z; - std::vector m_params; - }; -} +#pragma once + +#include +#include +#include + +namespace YAML +{ + struct Stream; + + enum REGEX_OP { REGEX_EMPTY, REGEX_MATCH, REGEX_RANGE, REGEX_OR, REGEX_AND, REGEX_NOT, REGEX_SEQ }; + + // simplified regular expressions + // . Only straightforward matches (no repeated characters) + // . Only matches from start of string + class RegEx + { + private: + struct Operator { + virtual ~Operator() {} + virtual int Match(const std::string& str, const RegEx& regex) const = 0; + virtual int Match(std::istream& in, const RegEx& regex) const = 0; + }; + + struct MatchOperator: public Operator { + virtual int Match(const std::string& str, const RegEx& regex) const; + virtual int Match(std::istream& in, const RegEx& regex) const; + }; + + struct RangeOperator: public Operator { + virtual int Match(const std::string& str, const RegEx& regex) const; + virtual int Match(std::istream& in, const RegEx& regex) const; + }; + + struct OrOperator: public Operator { + virtual int Match(const std::string& str, const RegEx& regex) const; + virtual int Match(std::istream& in, const RegEx& regex) const; + }; + + struct AndOperator: public Operator { + virtual int Match(const std::string& str, const RegEx& regex) const; + virtual int Match(std::istream& in, const RegEx& regex) const; + }; + + struct NotOperator: public Operator { + virtual int Match(const std::string& str, const RegEx& regex) const; + virtual int Match(std::istream& in, const RegEx& regex) const; + }; + + struct SeqOperator: public Operator { + virtual int Match(const std::string& str, const RegEx& regex) const; + virtual int Match(std::istream& in, const RegEx& regex) const; + }; + + public: + friend struct Operator; + + RegEx(); + RegEx(char ch); + RegEx(char a, char z); + RegEx(const std::string& str, REGEX_OP op = REGEX_SEQ); + RegEx(const RegEx& rhs); + ~RegEx(); + + RegEx& operator = (const RegEx& rhs); + + bool Matches(char ch) const; + bool Matches(const std::string& str) const; + bool Matches(std::istream& in) const; + bool Matches(Stream& in) const; + int Match(const std::string& str) const; + int Match(std::istream& in) const; + int Match(Stream& in) const; + + friend RegEx operator ! (const RegEx& ex); + friend RegEx operator || (const RegEx& ex1, const RegEx& ex2); + friend RegEx operator && (const RegEx& ex1, const RegEx& ex2); + friend RegEx operator + (const RegEx& ex1, const RegEx& ex2); + + private: + RegEx(REGEX_OP op); + void SetOp(); + + private: + REGEX_OP m_op; + Operator *m_pOp; + char m_a, m_z; + std::vector m_params; + }; +} diff --git a/src/scalar.cpp b/src/scalar.cpp index 56edb4a..ed8f032 100644 --- a/src/scalar.cpp +++ b/src/scalar.cpp @@ -1,108 +1,108 @@ -#include "crt.h" -#include "scalar.h" -#include "scanner.h" -#include "token.h" -#include "exceptions.h" -#include "node.h" -#include - -namespace YAML -{ - Scalar::Scalar() - { - } - - Scalar::~Scalar() - { - } - - void Scalar::Parse(Scanner *pScanner, const ParserState& state) - { - Token& token = pScanner->peek(); - m_data = token.value; - pScanner->pop(); - } - - void Scalar::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) - { - out << "\""; - for(unsigned i=0;i> i; - if(!data) - throw InvalidScalar(); - } - - void Scalar::Read(unsigned& u) - { - std::stringstream data(m_data); - data >> u; - if(!data) - throw InvalidScalar(); - } - - void Scalar::Read(long& l) - { - std::stringstream data(m_data); - data >> l; - if(!data) - throw InvalidScalar(); - } - - void Scalar::Read(float& f) - { - std::stringstream data(m_data); - data >> f; - if(!data) - throw InvalidScalar(); - } - - void Scalar::Read(double& d) - { - std::stringstream data(m_data); - data >> d; - if(!data) - throw InvalidScalar(); - } - - void Scalar::Read(char& c) - { - std::stringstream data(m_data); - data >> c; - if(!data) - throw InvalidScalar(); - } - - int Scalar::Compare(Content *pContent) - { - return -pContent->Compare(this); - } - - int Scalar::Compare(Scalar *pScalar) - { - if(m_data < pScalar->m_data) - return -1; - else if(m_data > pScalar->m_data) - return 1; - else - return 0; - } -} +#include "crt.h" +#include "scalar.h" +#include "scanner.h" +#include "token.h" +#include "exceptions.h" +#include "node.h" +#include + +namespace YAML +{ + Scalar::Scalar() + { + } + + Scalar::~Scalar() + { + } + + void Scalar::Parse(Scanner *pScanner, const ParserState& state) + { + Token& token = pScanner->peek(); + m_data = token.value; + pScanner->pop(); + } + + void Scalar::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) + { + out << "\""; + for(unsigned i=0;i> i; + if(!data) + throw InvalidScalar(); + } + + void Scalar::Read(unsigned& u) + { + std::stringstream data(m_data); + data >> u; + if(!data) + throw InvalidScalar(); + } + + void Scalar::Read(long& l) + { + std::stringstream data(m_data); + data >> l; + if(!data) + throw InvalidScalar(); + } + + void Scalar::Read(float& f) + { + std::stringstream data(m_data); + data >> f; + if(!data) + throw InvalidScalar(); + } + + void Scalar::Read(double& d) + { + std::stringstream data(m_data); + data >> d; + if(!data) + throw InvalidScalar(); + } + + void Scalar::Read(char& c) + { + std::stringstream data(m_data); + data >> c; + if(!data) + throw InvalidScalar(); + } + + int Scalar::Compare(Content *pContent) + { + return -pContent->Compare(this); + } + + int Scalar::Compare(Scalar *pScalar) + { + if(m_data < pScalar->m_data) + return -1; + else if(m_data > pScalar->m_data) + return 1; + else + return 0; + } +} diff --git a/src/scalar.h b/src/scalar.h index f33f8a5..ea6e055 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -1,37 +1,37 @@ -#pragma once - -#include "content.h" -#include - -namespace YAML -{ - class Scalar: public Content - { - public: - Scalar(); - virtual ~Scalar(); - - virtual void Parse(Scanner *pScanner, const ParserState& state); - virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); - - virtual bool IsScalar() const { return true; } - - // extraction - virtual void Read(std::string& s); - virtual void Read(int& i); - virtual void Read(unsigned& u); - virtual void Read(long& l); - virtual void Read(float& f); - virtual void Read(double& d); - virtual void Read(char& c); - - // ordering - virtual int Compare(Content *pContent); - virtual int Compare(Scalar *pScalar); - virtual int Compare(Sequence *pSeq) { return -1; } - virtual int Compare(Map *pMap) { return -1; } - - protected: - std::string m_data; - }; -} +#pragma once + +#include "content.h" +#include + +namespace YAML +{ + class Scalar: public Content + { + public: + Scalar(); + virtual ~Scalar(); + + virtual void Parse(Scanner *pScanner, const ParserState& state); + virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); + + virtual bool IsScalar() const { return true; } + + // extraction + virtual void Read(std::string& s); + virtual void Read(int& i); + virtual void Read(unsigned& u); + virtual void Read(long& l); + virtual void Read(float& f); + virtual void Read(double& d); + virtual void Read(char& c); + + // ordering + virtual int Compare(Content *pContent); + virtual int Compare(Scalar *pScalar); + virtual int Compare(Sequence *pSeq) { return -1; } + virtual int Compare(Map *pMap) { return -1; } + + protected: + std::string m_data; + }; +} diff --git a/src/scanner.cpp b/src/scanner.cpp index b800840..5aed8d5 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -1,276 +1,276 @@ -#include "crt.h" -#include "scanner.h" -#include "token.h" -#include "exceptions.h" -#include "exp.h" -#include - -namespace YAML -{ - Scanner::Scanner(std::istream& in) - : INPUT(in), m_startedStream(false), m_endedStream(false), m_simpleKeyAllowed(false), m_flowLevel(0) - { - } - - Scanner::~Scanner() - { - } - - // empty - // . Returns true if there are no more tokens to be read - bool Scanner::empty() - { - EnsureTokensInQueue(); - return m_tokens.empty(); - } - - // pop - // . Simply removes the next token on the queue. - void Scanner::pop() - { - EnsureTokensInQueue(); - if(!m_tokens.empty()) - m_tokens.pop(); - } - - // peek - // . Returns (but does not remove) the next token on the queue. - Token& Scanner::peek() - { - EnsureTokensInQueue(); - assert(!m_tokens.empty()); // should we be asserting here? I mean, we really just be checking - // if it's empty before peeking. - - return m_tokens.front(); - } - - // EnsureTokensInQueue - // . Scan until there's a valid token at the front of the queue, - // or we're sure the queue is empty. - void Scanner::EnsureTokensInQueue() - { - while(1) { - if(!m_tokens.empty()) { - Token& token = m_tokens.front(); - - // if this guy's valid, then we're done - if(token.status == TS_VALID) - return; - - // here's where we clean up the impossible tokens - if(token.status == TS_INVALID) { - m_tokens.pop(); - continue; - } - - // note: what's left are the unverified tokens - } - - // no token? maybe we've actually finished - if(m_endedStream) - return; - - // no? then scan... - ScanNextToken(); - } - } - - // ScanNextToken - // . The main scanning function; here we branch out and - // scan whatever the next token should be. - void Scanner::ScanNextToken() - { - if(m_endedStream) - return; - - if(!m_startedStream) - return StartStream(); - - // get rid of whitespace, etc. (in between tokens it should be irrelevent) - ScanToNextToken(); - - // check the latest simple key - VerifySimpleKey(); - - // maybe need to end some blocks - PopIndentTo(INPUT.column); - - // ***** - // And now branch based on the next few characters! - // ***** - - // end of stream - if(INPUT.peek() == EOF) - return EndStream(); - - if(INPUT.column == 0 && INPUT.peek() == Keys::Directive) - return ScanDirective(); - - // document token - if(INPUT.column == 0 && Exp::DocStart.Matches(INPUT)) - return ScanDocStart(); - - if(INPUT.column == 0 && Exp::DocEnd.Matches(INPUT)) - return ScanDocEnd(); - - // flow start/end/entry - if(INPUT.peek() == Keys::FlowSeqStart || INPUT.peek() == Keys::FlowMapStart) - return ScanFlowStart(); - - if(INPUT.peek() == Keys::FlowSeqEnd || INPUT.peek() == Keys::FlowMapEnd) - return ScanFlowEnd(); - - if(INPUT.peek() == Keys::FlowEntry) - return ScanFlowEntry(); - - // block/map stuff - if(Exp::BlockEntry.Matches(INPUT)) - return ScanBlockEntry(); - - if((m_flowLevel == 0 ? Exp::Key : Exp::KeyInFlow).Matches(INPUT)) - return ScanKey(); - - if((m_flowLevel == 0 ? Exp::Value : Exp::ValueInFlow).Matches(INPUT)) - return ScanValue(); - - // alias/anchor - if(INPUT.peek() == Keys::Alias || INPUT.peek() == Keys::Anchor) - return ScanAnchorOrAlias(); - - // tag - if(INPUT.peek() == Keys::Tag) - return ScanTag(); - - // special scalars - if(m_flowLevel == 0 && (INPUT.peek() == Keys::LiteralScalar || INPUT.peek() == Keys::FoldedScalar)) - return ScanBlockScalar(); - - if(INPUT.peek() == '\'' || INPUT.peek() == '\"') - return ScanQuotedScalar(); - - // plain scalars - if((m_flowLevel == 0 ? Exp::PlainScalar : Exp::PlainScalarInFlow).Matches(INPUT)) - return ScanPlainScalar(); - - // don't know what it is! - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::UNKNOWN_TOKEN); - } - - // ScanToNextToken - // . Eats input until we reach the next token-like thing. - void Scanner::ScanToNextToken() - { - while(1) { - // first eat whitespace - while(IsWhitespaceToBeEaten(INPUT.peek())) - INPUT.eat(1); - - // then eat a comment - if(Exp::Comment.Matches(INPUT)) { - // eat until line break - while(INPUT && !Exp::Break.Matches(INPUT)) - INPUT.eat(1); - } - - // if it's NOT a line break, then we're done! - if(!Exp::Break.Matches(INPUT)) - break; - - // otherwise, let's eat the line break and keep going - int n = Exp::Break.Match(INPUT); - INPUT.eat(n); - - // oh yeah, and let's get rid of that simple key - VerifySimpleKey(); - - // new line - we may be able to accept a simple key now - if(m_flowLevel == 0) - m_simpleKeyAllowed = true; - } - } - - /////////////////////////////////////////////////////////////////////// - // Misc. helpers - - // IsWhitespaceToBeEaten - // . We can eat whitespace if: - // 1. It's a space - // 2. It's a tab, and we're either: - // a. In the flow context - // b. In the block context but not where a simple key could be allowed - // (i.e., not at the beginning of a line, or following '-', '?', or ':') - bool Scanner::IsWhitespaceToBeEaten(char ch) - { - if(ch == ' ') - return true; - - if(ch == '\t' && (m_flowLevel >= 0 || !m_simpleKeyAllowed)) - return true; - - return false; - } - - // StartStream - // . Set the initial conditions for starting a stream. - void Scanner::StartStream() - { - m_startedStream = true; - m_simpleKeyAllowed = true; - m_indents.push(-1); - } - - // EndStream - // . Close out the stream, finish up, etc. - void Scanner::EndStream() - { - // force newline - if(INPUT.column > 0) - INPUT.column = 0; - - PopIndentTo(-1); - VerifyAllSimpleKeys(); - - m_simpleKeyAllowed = false; - m_endedStream = true; - } - - // PushIndentTo - // . Pushes an indentation onto the stack, and enqueues the - // proper token (sequence start or mapping start). - // . Returns the token it generates (if any). - Token *Scanner::PushIndentTo(int column, bool sequence) - { - // are we in flow? - if(m_flowLevel > 0) - return 0; - - // is this actually an indentation? - if(column <= m_indents.top()) - return 0; - - // now push - m_indents.push(column); - if(sequence) - m_tokens.push(Token(TT_BLOCK_SEQ_START, INPUT.line, INPUT.column)); - else - m_tokens.push(Token(TT_BLOCK_MAP_START, INPUT.line, INPUT.column)); - - return &m_tokens.back(); - } - - // PopIndentTo - // . Pops indentations off the stack until we reach 'column' indentation, - // and enqueues the proper token each time. - void Scanner::PopIndentTo(int column) - { - // are we in flow? - if(m_flowLevel > 0) - return; - - // now pop away - while(!m_indents.empty() && m_indents.top() > column) { - m_indents.pop(); - m_tokens.push(Token(TT_BLOCK_END, INPUT.line, INPUT.column)); - } - } -} +#include "crt.h" +#include "scanner.h" +#include "token.h" +#include "exceptions.h" +#include "exp.h" +#include + +namespace YAML +{ + Scanner::Scanner(std::istream& in) + : INPUT(in), m_startedStream(false), m_endedStream(false), m_simpleKeyAllowed(false), m_flowLevel(0) + { + } + + Scanner::~Scanner() + { + } + + // empty + // . Returns true if there are no more tokens to be read + bool Scanner::empty() + { + EnsureTokensInQueue(); + return m_tokens.empty(); + } + + // pop + // . Simply removes the next token on the queue. + void Scanner::pop() + { + EnsureTokensInQueue(); + if(!m_tokens.empty()) + m_tokens.pop(); + } + + // peek + // . Returns (but does not remove) the next token on the queue. + Token& Scanner::peek() + { + EnsureTokensInQueue(); + assert(!m_tokens.empty()); // should we be asserting here? I mean, we really just be checking + // if it's empty before peeking. + + return m_tokens.front(); + } + + // EnsureTokensInQueue + // . Scan until there's a valid token at the front of the queue, + // or we're sure the queue is empty. + void Scanner::EnsureTokensInQueue() + { + while(1) { + if(!m_tokens.empty()) { + Token& token = m_tokens.front(); + + // if this guy's valid, then we're done + if(token.status == TS_VALID) + return; + + // here's where we clean up the impossible tokens + if(token.status == TS_INVALID) { + m_tokens.pop(); + continue; + } + + // note: what's left are the unverified tokens + } + + // no token? maybe we've actually finished + if(m_endedStream) + return; + + // no? then scan... + ScanNextToken(); + } + } + + // ScanNextToken + // . The main scanning function; here we branch out and + // scan whatever the next token should be. + void Scanner::ScanNextToken() + { + if(m_endedStream) + return; + + if(!m_startedStream) + return StartStream(); + + // get rid of whitespace, etc. (in between tokens it should be irrelevent) + ScanToNextToken(); + + // check the latest simple key + VerifySimpleKey(); + + // maybe need to end some blocks + PopIndentTo(INPUT.column); + + // ***** + // And now branch based on the next few characters! + // ***** + + // end of stream + if(INPUT.peek() == EOF) + return EndStream(); + + if(INPUT.column == 0 && INPUT.peek() == Keys::Directive) + return ScanDirective(); + + // document token + if(INPUT.column == 0 && Exp::DocStart.Matches(INPUT)) + return ScanDocStart(); + + if(INPUT.column == 0 && Exp::DocEnd.Matches(INPUT)) + return ScanDocEnd(); + + // flow start/end/entry + if(INPUT.peek() == Keys::FlowSeqStart || INPUT.peek() == Keys::FlowMapStart) + return ScanFlowStart(); + + if(INPUT.peek() == Keys::FlowSeqEnd || INPUT.peek() == Keys::FlowMapEnd) + return ScanFlowEnd(); + + if(INPUT.peek() == Keys::FlowEntry) + return ScanFlowEntry(); + + // block/map stuff + if(Exp::BlockEntry.Matches(INPUT)) + return ScanBlockEntry(); + + if((m_flowLevel == 0 ? Exp::Key : Exp::KeyInFlow).Matches(INPUT)) + return ScanKey(); + + if((m_flowLevel == 0 ? Exp::Value : Exp::ValueInFlow).Matches(INPUT)) + return ScanValue(); + + // alias/anchor + if(INPUT.peek() == Keys::Alias || INPUT.peek() == Keys::Anchor) + return ScanAnchorOrAlias(); + + // tag + if(INPUT.peek() == Keys::Tag) + return ScanTag(); + + // special scalars + if(m_flowLevel == 0 && (INPUT.peek() == Keys::LiteralScalar || INPUT.peek() == Keys::FoldedScalar)) + return ScanBlockScalar(); + + if(INPUT.peek() == '\'' || INPUT.peek() == '\"') + return ScanQuotedScalar(); + + // plain scalars + if((m_flowLevel == 0 ? Exp::PlainScalar : Exp::PlainScalarInFlow).Matches(INPUT)) + return ScanPlainScalar(); + + // don't know what it is! + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::UNKNOWN_TOKEN); + } + + // ScanToNextToken + // . Eats input until we reach the next token-like thing. + void Scanner::ScanToNextToken() + { + while(1) { + // first eat whitespace + while(IsWhitespaceToBeEaten(INPUT.peek())) + INPUT.eat(1); + + // then eat a comment + if(Exp::Comment.Matches(INPUT)) { + // eat until line break + while(INPUT && !Exp::Break.Matches(INPUT)) + INPUT.eat(1); + } + + // if it's NOT a line break, then we're done! + if(!Exp::Break.Matches(INPUT)) + break; + + // otherwise, let's eat the line break and keep going + int n = Exp::Break.Match(INPUT); + INPUT.eat(n); + + // oh yeah, and let's get rid of that simple key + VerifySimpleKey(); + + // new line - we may be able to accept a simple key now + if(m_flowLevel == 0) + m_simpleKeyAllowed = true; + } + } + + /////////////////////////////////////////////////////////////////////// + // Misc. helpers + + // IsWhitespaceToBeEaten + // . We can eat whitespace if: + // 1. It's a space + // 2. It's a tab, and we're either: + // a. In the flow context + // b. In the block context but not where a simple key could be allowed + // (i.e., not at the beginning of a line, or following '-', '?', or ':') + bool Scanner::IsWhitespaceToBeEaten(char ch) + { + if(ch == ' ') + return true; + + if(ch == '\t' && (m_flowLevel >= 0 || !m_simpleKeyAllowed)) + return true; + + return false; + } + + // StartStream + // . Set the initial conditions for starting a stream. + void Scanner::StartStream() + { + m_startedStream = true; + m_simpleKeyAllowed = true; + m_indents.push(-1); + } + + // EndStream + // . Close out the stream, finish up, etc. + void Scanner::EndStream() + { + // force newline + if(INPUT.column > 0) + INPUT.column = 0; + + PopIndentTo(-1); + VerifyAllSimpleKeys(); + + m_simpleKeyAllowed = false; + m_endedStream = true; + } + + // PushIndentTo + // . Pushes an indentation onto the stack, and enqueues the + // proper token (sequence start or mapping start). + // . Returns the token it generates (if any). + Token *Scanner::PushIndentTo(int column, bool sequence) + { + // are we in flow? + if(m_flowLevel > 0) + return 0; + + // is this actually an indentation? + if(column <= m_indents.top()) + return 0; + + // now push + m_indents.push(column); + if(sequence) + m_tokens.push(Token(TT_BLOCK_SEQ_START, INPUT.line, INPUT.column)); + else + m_tokens.push(Token(TT_BLOCK_MAP_START, INPUT.line, INPUT.column)); + + return &m_tokens.back(); + } + + // PopIndentTo + // . Pops indentations off the stack until we reach 'column' indentation, + // and enqueues the proper token each time. + void Scanner::PopIndentTo(int column) + { + // are we in flow? + if(m_flowLevel > 0) + return; + + // now pop away + while(!m_indents.empty() && m_indents.top() > column) { + m_indents.pop(); + m_tokens.push(Token(TT_BLOCK_END, INPUT.line, INPUT.column)); + } + } +} diff --git a/src/scanner.h b/src/scanner.h index 805b82d..8764719 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -1,85 +1,85 @@ -#pragma once - -#include -#include -#include -#include -#include -#include "stream.h" -#include "token.h" - -namespace YAML -{ - class Scanner - { - public: - Scanner(std::istream& in); - ~Scanner(); - - // token queue management (hopefully this looks kinda stl-ish) - bool empty(); - void pop(); - Token& peek(); - - private: - // scanning - void EnsureTokensInQueue(); - void ScanNextToken(); - void ScanToNextToken(); - void StartStream(); - void EndStream(); - Token *PushIndentTo(int column, bool sequence); - void PopIndentTo(int column); - - // checking input - void InsertSimpleKey(); - bool VerifySimpleKey(); - void VerifyAllSimpleKeys(); - - bool IsWhitespaceToBeEaten(char ch); - - struct SimpleKey { - SimpleKey(int pos_, int line_, int column_, int flowLevel_); - - void Validate(); - void Invalidate(); - - int pos, line, column, flowLevel; - Token *pMapStart, *pKey; - }; - - // and the tokens - void ScanDirective(); - void ScanDocStart(); - void ScanDocEnd(); - void ScanBlockSeqStart(); - void ScanBlockMapSTart(); - void ScanBlockEnd(); - void ScanBlockEntry(); - void ScanFlowStart(); - void ScanFlowEnd(); - void ScanFlowEntry(); - void ScanKey(); - void ScanValue(); - void ScanAnchorOrAlias(); - void ScanTag(); - void ScanPlainScalar(); - void ScanQuotedScalar(); - void ScanBlockScalar(); - - private: - // the stream - Stream INPUT; - - // the output (tokens) - std::queue m_tokens; - - // state info - bool m_startedStream, m_endedStream; - bool m_simpleKeyAllowed; - int m_flowLevel; // number of unclosed '[' and '{' indicators - bool m_isLastKeyValid; - std::stack m_simpleKeys; - std::stack m_indents; - }; -} +#pragma once + +#include +#include +#include +#include +#include +#include "stream.h" +#include "token.h" + +namespace YAML +{ + class Scanner + { + public: + Scanner(std::istream& in); + ~Scanner(); + + // token queue management (hopefully this looks kinda stl-ish) + bool empty(); + void pop(); + Token& peek(); + + private: + // scanning + void EnsureTokensInQueue(); + void ScanNextToken(); + void ScanToNextToken(); + void StartStream(); + void EndStream(); + Token *PushIndentTo(int column, bool sequence); + void PopIndentTo(int column); + + // checking input + void InsertSimpleKey(); + bool VerifySimpleKey(); + void VerifyAllSimpleKeys(); + + bool IsWhitespaceToBeEaten(char ch); + + struct SimpleKey { + SimpleKey(int pos_, int line_, int column_, int flowLevel_); + + void Validate(); + void Invalidate(); + + int pos, line, column, flowLevel; + Token *pMapStart, *pKey; + }; + + // and the tokens + void ScanDirective(); + void ScanDocStart(); + void ScanDocEnd(); + void ScanBlockSeqStart(); + void ScanBlockMapSTart(); + void ScanBlockEnd(); + void ScanBlockEntry(); + void ScanFlowStart(); + void ScanFlowEnd(); + void ScanFlowEntry(); + void ScanKey(); + void ScanValue(); + void ScanAnchorOrAlias(); + void ScanTag(); + void ScanPlainScalar(); + void ScanQuotedScalar(); + void ScanBlockScalar(); + + private: + // the stream + Stream INPUT; + + // the output (tokens) + std::queue m_tokens; + + // state info + bool m_startedStream, m_endedStream; + bool m_simpleKeyAllowed; + int m_flowLevel; // number of unclosed '[' and '{' indicators + bool m_isLastKeyValid; + std::stack m_simpleKeys; + std::stack m_indents; + }; +} diff --git a/src/scanscalar.cpp b/src/scanscalar.cpp index 70abef4..b318f00 100644 --- a/src/scanscalar.cpp +++ b/src/scanscalar.cpp @@ -1,154 +1,154 @@ -#include "crt.h" -#include "scanscalar.h" -#include "scanner.h" -#include "exp.h" -#include "exceptions.h" -#include "token.h" - -namespace YAML -{ - // ScanScalar - // . This is where the scalar magic happens. - // - // . We do the scanning in three phases: - // 1. Scan until newline - // 2. Eat newline - // 3. Scan leading blanks. - // - // . Depending on the parameters given, we store or stop - // and different places in the above flow. - std::string ScanScalar(Stream& INPUT, ScanScalarParams& params) - { - bool foundNonEmptyLine = false, pastOpeningBreak = false; - bool emptyLine = false, moreIndented = false; - std::string scalar; - params.leadingSpaces = false; - - while(INPUT) { - // ******************************** - // Phase #1: scan until line ending - while(!params.end.Matches(INPUT) && !Exp::Break.Matches(INPUT)) { - if(INPUT.peek() == EOF) - break; - - // document indicator? - if(INPUT.column == 0 && Exp::DocIndicator.Matches(INPUT)) { - if(params.onDocIndicator == BREAK) - break; - else if(params.onDocIndicator == THROW) - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::DOC_IN_SCALAR); - } - - foundNonEmptyLine = true; - pastOpeningBreak = true; - - // escaped newline? (only if we're escaping on slash) - if(params.escape == '\\' && Exp::EscBreak.Matches(INPUT)) { - int n = Exp::EscBreak.Match(INPUT); - INPUT.eat(n); - continue; - } - - // escape this? - if(INPUT.peek() == params.escape) { - scalar += Exp::Escape(INPUT); - continue; - } - - // otherwise, just add the damn character - scalar += INPUT.get(); - } - - // eof? if we're looking to eat something, then we throw - if(INPUT.peek() == EOF) { - if(params.eatEnd) - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::EOF_IN_SCALAR); - break; - } - - // doc indicator? - if(params.onDocIndicator == BREAK && INPUT.column == 0 && Exp::DocIndicator.Matches(INPUT)) - break; - - // are we done via character match? - int n = params.end.Match(INPUT); - if(n >= 0) { - if(params.eatEnd) - INPUT.eat(n); - break; - } - - // ******************************** - // Phase #2: eat line ending - n = Exp::Break.Match(INPUT); - INPUT.eat(n); - - // ******************************** - // Phase #3: scan initial spaces - - // first the required indentation - while(INPUT.peek() == ' ' && (INPUT.column < params.indent || (params.detectIndent && !foundNonEmptyLine))) - INPUT.eat(1); - - // update indent if we're auto-detecting - if(params.detectIndent && !foundNonEmptyLine) - params.indent = std::max(params.indent, INPUT.column); - - // and then the rest of the whitespace - while(Exp::Blank.Matches(INPUT)) { - // we check for tabs that masquerade as indentation - if(INPUT.peek() == '\t'&& INPUT.column < params.indent && params.onTabInIndentation == THROW) - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::TAB_IN_INDENTATION); - - if(!params.eatLeadingWhitespace) - break; - - INPUT.eat(1); - } - - // was this an empty line? - bool nextEmptyLine = Exp::Break.Matches(INPUT); - bool nextMoreIndented = (INPUT.peek() == ' '); - - // for block scalars, we always start with a newline, so we should ignore it (not fold or keep) - bool useNewLine = pastOpeningBreak; - // and for folded scalars, we don't fold the very last newline to a space - if(params.fold && !emptyLine && INPUT.column < params.indent) - useNewLine = false; - - if(useNewLine) { - if(params.fold && !emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented) - scalar += " "; - else - scalar += "\n"; - } - - emptyLine = nextEmptyLine; - moreIndented = nextMoreIndented; - pastOpeningBreak = true; - - // are we done via indentation? - if(!emptyLine && INPUT.column < params.indent) { - params.leadingSpaces = true; - break; - } - } - - // post-processing - if(params.trimTrailingSpaces) { - unsigned pos = scalar.find_last_not_of(' '); - if(pos < scalar.size()) - scalar.erase(pos + 1); - } - - if(params.chomp <= 0) { - unsigned pos = scalar.find_last_not_of('\n'); - if(params.chomp == 0 && pos + 1 < scalar.size()) - scalar.erase(pos + 2); - else if(params.chomp == -1 && pos < scalar.size()) - scalar.erase(pos + 1); - } - - return scalar; - } -} +#include "crt.h" +#include "scanscalar.h" +#include "scanner.h" +#include "exp.h" +#include "exceptions.h" +#include "token.h" + +namespace YAML +{ + // ScanScalar + // . This is where the scalar magic happens. + // + // . We do the scanning in three phases: + // 1. Scan until newline + // 2. Eat newline + // 3. Scan leading blanks. + // + // . Depending on the parameters given, we store or stop + // and different places in the above flow. + std::string ScanScalar(Stream& INPUT, ScanScalarParams& params) + { + bool foundNonEmptyLine = false, pastOpeningBreak = false; + bool emptyLine = false, moreIndented = false; + std::string scalar; + params.leadingSpaces = false; + + while(INPUT) { + // ******************************** + // Phase #1: scan until line ending + while(!params.end.Matches(INPUT) && !Exp::Break.Matches(INPUT)) { + if(INPUT.peek() == EOF) + break; + + // document indicator? + if(INPUT.column == 0 && Exp::DocIndicator.Matches(INPUT)) { + if(params.onDocIndicator == BREAK) + break; + else if(params.onDocIndicator == THROW) + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::DOC_IN_SCALAR); + } + + foundNonEmptyLine = true; + pastOpeningBreak = true; + + // escaped newline? (only if we're escaping on slash) + if(params.escape == '\\' && Exp::EscBreak.Matches(INPUT)) { + int n = Exp::EscBreak.Match(INPUT); + INPUT.eat(n); + continue; + } + + // escape this? + if(INPUT.peek() == params.escape) { + scalar += Exp::Escape(INPUT); + continue; + } + + // otherwise, just add the damn character + scalar += INPUT.get(); + } + + // eof? if we're looking to eat something, then we throw + if(INPUT.peek() == EOF) { + if(params.eatEnd) + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::EOF_IN_SCALAR); + break; + } + + // doc indicator? + if(params.onDocIndicator == BREAK && INPUT.column == 0 && Exp::DocIndicator.Matches(INPUT)) + break; + + // are we done via character match? + int n = params.end.Match(INPUT); + if(n >= 0) { + if(params.eatEnd) + INPUT.eat(n); + break; + } + + // ******************************** + // Phase #2: eat line ending + n = Exp::Break.Match(INPUT); + INPUT.eat(n); + + // ******************************** + // Phase #3: scan initial spaces + + // first the required indentation + while(INPUT.peek() == ' ' && (INPUT.column < params.indent || (params.detectIndent && !foundNonEmptyLine))) + INPUT.eat(1); + + // update indent if we're auto-detecting + if(params.detectIndent && !foundNonEmptyLine) + params.indent = std::max(params.indent, INPUT.column); + + // and then the rest of the whitespace + while(Exp::Blank.Matches(INPUT)) { + // we check for tabs that masquerade as indentation + if(INPUT.peek() == '\t'&& INPUT.column < params.indent && params.onTabInIndentation == THROW) + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::TAB_IN_INDENTATION); + + if(!params.eatLeadingWhitespace) + break; + + INPUT.eat(1); + } + + // was this an empty line? + bool nextEmptyLine = Exp::Break.Matches(INPUT); + bool nextMoreIndented = (INPUT.peek() == ' '); + + // for block scalars, we always start with a newline, so we should ignore it (not fold or keep) + bool useNewLine = pastOpeningBreak; + // and for folded scalars, we don't fold the very last newline to a space + if(params.fold && !emptyLine && INPUT.column < params.indent) + useNewLine = false; + + if(useNewLine) { + if(params.fold && !emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented) + scalar += " "; + else + scalar += "\n"; + } + + emptyLine = nextEmptyLine; + moreIndented = nextMoreIndented; + pastOpeningBreak = true; + + // are we done via indentation? + if(!emptyLine && INPUT.column < params.indent) { + params.leadingSpaces = true; + break; + } + } + + // post-processing + if(params.trimTrailingSpaces) { + unsigned pos = scalar.find_last_not_of(' '); + if(pos < scalar.size()) + scalar.erase(pos + 1); + } + + if(params.chomp <= 0) { + unsigned pos = scalar.find_last_not_of('\n'); + if(params.chomp == 0 && pos + 1 < scalar.size()) + scalar.erase(pos + 2); + else if(params.chomp == -1 && pos < scalar.size()) + scalar.erase(pos + 1); + } + + return scalar; + } +} diff --git a/src/scanscalar.h b/src/scanscalar.h index b2c4327..ee66213 100644 --- a/src/scanscalar.h +++ b/src/scanscalar.h @@ -1,35 +1,35 @@ -#pragma once - -#include -#include "regex.h" -#include "stream.h" - -namespace YAML -{ - enum CHOMP { STRIP = -1, CLIP, KEEP }; - enum ACTION { NONE, BREAK, THROW }; - - struct ScanScalarParams { - ScanScalarParams(): eatEnd(false), indent(0), detectIndent(false), eatLeadingWhitespace(0), escape(0), fold(false), - trimTrailingSpaces(0), chomp(CLIP), onDocIndicator(NONE), onTabInIndentation(NONE), leadingSpaces(false) {} - - // input: - RegEx end; // what condition ends this scalar? - bool eatEnd; // should we eat that condition when we see it? - int indent; // what level of indentation should be eaten and ignored? - bool detectIndent; // should we try to autodetect the indent? - bool eatLeadingWhitespace; // should we continue eating this delicious indentation after 'indent' spaces? - char escape; // what character do we escape on (i.e., slash or single quote) (0 for none) - bool fold; // do we fold line ends? - bool trimTrailingSpaces; // do we remove all trailing spaces (at the very end) - CHOMP chomp; // do we strip, clip, or keep trailing newlines (at the very end) - // Note: strip means kill all, clip means keep at most one, keep means keep all - ACTION onDocIndicator; // what do we do if we see a document indicator? - ACTION onTabInIndentation; // what do we do if we see a tab where we should be seeing indentation spaces - - // output: - bool leadingSpaces; - }; - - std::string ScanScalar(Stream& INPUT, ScanScalarParams& info); -} +#pragma once + +#include +#include "regex.h" +#include "stream.h" + +namespace YAML +{ + enum CHOMP { STRIP = -1, CLIP, KEEP }; + enum ACTION { NONE, BREAK, THROW }; + + struct ScanScalarParams { + ScanScalarParams(): eatEnd(false), indent(0), detectIndent(false), eatLeadingWhitespace(0), escape(0), fold(false), + trimTrailingSpaces(0), chomp(CLIP), onDocIndicator(NONE), onTabInIndentation(NONE), leadingSpaces(false) {} + + // input: + RegEx end; // what condition ends this scalar? + bool eatEnd; // should we eat that condition when we see it? + int indent; // what level of indentation should be eaten and ignored? + bool detectIndent; // should we try to autodetect the indent? + bool eatLeadingWhitespace; // should we continue eating this delicious indentation after 'indent' spaces? + char escape; // what character do we escape on (i.e., slash or single quote) (0 for none) + bool fold; // do we fold line ends? + bool trimTrailingSpaces; // do we remove all trailing spaces (at the very end) + CHOMP chomp; // do we strip, clip, or keep trailing newlines (at the very end) + // Note: strip means kill all, clip means keep at most one, keep means keep all + ACTION onDocIndicator; // what do we do if we see a document indicator? + ACTION onTabInIndentation; // what do we do if we see a tab where we should be seeing indentation spaces + + // output: + bool leadingSpaces; + }; + + std::string ScanScalar(Stream& INPUT, ScanScalarParams& info); +} diff --git a/src/scantoken.cpp b/src/scantoken.cpp index 31489ae..39f6720 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -1,405 +1,405 @@ -#include "crt.h" -#include "scanner.h" -#include "token.h" -#include "exceptions.h" -#include "exp.h" -#include "scanscalar.h" -#include - -namespace YAML -{ - /////////////////////////////////////////////////////////////////////// - // Specialization for scanning specific tokens - - // Directive - // . Note: no semantic checking is done here (that's for the parser to do) - void Scanner::ScanDirective() - { - std::string name; - std::vector params; - - // pop indents and simple keys - PopIndentTo(-1); - VerifyAllSimpleKeys(); - - m_simpleKeyAllowed = false; - - // store pos and eat indicator - int line = INPUT.line, column = INPUT.column; - INPUT.eat(1); - - // read name - while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT)) - name += INPUT.get(); - - // read parameters - while(1) { - // first get rid of whitespace - while(Exp::Blank.Matches(INPUT)) - INPUT.eat(1); - - // break on newline or comment - if(INPUT.peek() == EOF || Exp::Break.Matches(INPUT) || Exp::Comment.Matches(INPUT)) - break; - - // now read parameter - std::string param; - while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT)) - param += INPUT.get(); - - params.push_back(param); - } - - Token token(TT_DIRECTIVE, line, column); - token.value = name; - token.params = params; - m_tokens.push(token); - } - - // DocStart - void Scanner::ScanDocStart() - { - PopIndentTo(INPUT.column); - VerifyAllSimpleKeys(); - m_simpleKeyAllowed = false; - - // eat - int line = INPUT.line, column = INPUT.column; - INPUT.eat(3); - m_tokens.push(Token(TT_DOC_START, line, column)); - } - - // DocEnd - void Scanner::ScanDocEnd() - { - PopIndentTo(-1); - VerifyAllSimpleKeys(); - m_simpleKeyAllowed = false; - - // eat - int line = INPUT.line, column = INPUT.column; - INPUT.eat(3); - m_tokens.push(Token(TT_DOC_END, line, column)); - } - - // FlowStart - void Scanner::ScanFlowStart() - { - // flows can be simple keys - InsertSimpleKey(); - m_flowLevel++; - m_simpleKeyAllowed = true; - - // eat - int line = INPUT.line, column = INPUT.column; - char ch = INPUT.get(); - TOKEN_TYPE type = (ch == Keys::FlowSeqStart ? TT_FLOW_SEQ_START : TT_FLOW_MAP_START); - m_tokens.push(Token(type, line, column)); - } - - // FlowEnd - void Scanner::ScanFlowEnd() - { - if(m_flowLevel == 0) - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::FLOW_END); - - m_flowLevel--; - m_simpleKeyAllowed = false; - - // eat - int line = INPUT.line, column = INPUT.column; - char ch = INPUT.get(); - TOKEN_TYPE type = (ch == Keys::FlowSeqEnd ? TT_FLOW_SEQ_END : TT_FLOW_MAP_END); - m_tokens.push(Token(type, line, column)); - } - - // FlowEntry - void Scanner::ScanFlowEntry() - { - m_simpleKeyAllowed = true; - - // eat - int line = INPUT.line, column = INPUT.column; - INPUT.eat(1); - m_tokens.push(Token(TT_FLOW_ENTRY, line, column)); - } - - // BlockEntry - void Scanner::ScanBlockEntry() - { - // we better be in the block context! - if(m_flowLevel > 0) - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::BLOCK_ENTRY); - - // can we put it here? - if(!m_simpleKeyAllowed) - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::BLOCK_ENTRY); - - PushIndentTo(INPUT.column, true); - m_simpleKeyAllowed = true; - - // eat - int line = INPUT.line, column = INPUT.column; - INPUT.eat(1); - m_tokens.push(Token(TT_BLOCK_ENTRY, line, column)); - } - - // Key - void Scanner::ScanKey() - { - // handle keys diffently in the block context (and manage indents) - if(m_flowLevel == 0) { - if(!m_simpleKeyAllowed) - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::MAP_KEY); - - PushIndentTo(INPUT.column, false); - } - - // can only put a simple key here if we're in block context - if(m_flowLevel == 0) - m_simpleKeyAllowed = true; - else - m_simpleKeyAllowed = false; - - // eat - int line = INPUT.line, column = INPUT.column; - INPUT.eat(1); - m_tokens.push(Token(TT_KEY, line, column)); - } - - // Value - void Scanner::ScanValue() - { - // does this follow a simple key? - if(m_isLastKeyValid) { - // can't follow a simple key with another simple key (dunno why, though - it seems fine) - m_simpleKeyAllowed = false; - } else { - // handle values diffently in the block context (and manage indents) - if(m_flowLevel == 0) { - if(!m_simpleKeyAllowed) - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::MAP_VALUE); - - PushIndentTo(INPUT.column, false); - } - - // can only put a simple key here if we're in block context - if(m_flowLevel == 0) - m_simpleKeyAllowed = true; - else - m_simpleKeyAllowed = false; - } - - // eat - int line = INPUT.line, column = INPUT.column; - INPUT.eat(1); - m_tokens.push(Token(TT_VALUE, line, column)); - } - - // AnchorOrAlias - void Scanner::ScanAnchorOrAlias() - { - bool alias; - std::string name; - - // insert a potential simple key - if(m_simpleKeyAllowed) - InsertSimpleKey(); - m_simpleKeyAllowed = false; - - // eat the indicator - int line = INPUT.line, column = INPUT.column; - char indicator = INPUT.get(); - alias = (indicator == Keys::Alias); - - // now eat the content - while(Exp::AlphaNumeric.Matches(INPUT)) - name += INPUT.get(); - - // we need to have read SOMETHING! - if(name.empty()) - throw ParserException(INPUT.line, INPUT.column, alias ? ErrorMsg::ALIAS_NOT_FOUND : ErrorMsg::ANCHOR_NOT_FOUND); - - // and needs to end correctly - if(INPUT.peek() != EOF && !Exp::AnchorEnd.Matches(INPUT)) - throw ParserException(INPUT.line, INPUT.column, alias ? ErrorMsg::CHAR_IN_ALIAS : ErrorMsg::CHAR_IN_ANCHOR); - - // and we're done - Token token(alias ? TT_ALIAS : TT_ANCHOR, line, column); - token.value = name; - m_tokens.push(token); - } - - // Tag - void Scanner::ScanTag() - { - std::string handle, suffix; - - // insert a potential simple key - if(m_simpleKeyAllowed) - InsertSimpleKey(); - m_simpleKeyAllowed = false; - - // eat the indicator - int line = INPUT.line, column = INPUT.column; - handle += INPUT.get(); - - // read the handle - while(INPUT.peek() != EOF && INPUT.peek() != Keys::Tag && !Exp::BlankOrBreak.Matches(INPUT)) - handle += INPUT.get(); - - // is there a suffix? - if(INPUT.peek() == Keys::Tag) { - // eat the indicator - handle += INPUT.get(); - - // then read it - while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT)) - suffix += INPUT.get(); - } else { - // this is a bit weird: we keep just the '!' as the handle and move the rest to the suffix - suffix = handle.substr(1); - handle = "!"; - } - - Token token(TT_TAG, line, column); - token.value = handle; - token.params.push_back(suffix); - m_tokens.push(token); - } - - // PlainScalar - void Scanner::ScanPlainScalar() - { - std::string scalar; - - // set up the scanning parameters - ScanScalarParams params; - params.end = (m_flowLevel > 0 ? Exp::EndScalarInFlow : Exp::EndScalar) || (Exp::BlankOrBreak + Exp::Comment); - params.eatEnd = false; - params.indent = (m_flowLevel > 0 ? 0 : m_indents.top() + 1); - params.fold = true; - params.eatLeadingWhitespace = true; - params.trimTrailingSpaces = true; - params.chomp = CLIP; - params.onDocIndicator = BREAK; - params.onTabInIndentation = THROW; - - // insert a potential simple key - if(m_simpleKeyAllowed) - InsertSimpleKey(); - - int line = INPUT.line, column = INPUT.column; - scalar = ScanScalar(INPUT, params); - - // can have a simple key only if we ended the scalar by starting a new line - m_simpleKeyAllowed = params.leadingSpaces; - - // finally, check and see if we ended on an illegal character - //if(Exp::IllegalCharInScalar.Matches(INPUT)) - // throw ParserException(INPUT.line, INPUT.column, ErrorMsg::CHAR_IN_SCALAR); - - Token token(TT_SCALAR, line, column); - token.value = scalar; - m_tokens.push(token); - } - - // QuotedScalar - void Scanner::ScanQuotedScalar() - { - std::string scalar; - - // eat single or double quote - char quote = INPUT.get(); - bool single = (quote == '\''); - - // setup the scanning parameters - ScanScalarParams params; - params.end = (single ? RegEx(quote) && !Exp::EscSingleQuote : RegEx(quote)); - params.eatEnd = true; - params.escape = (single ? '\'' : '\\'); - params.indent = 0; - params.fold = true; - params.eatLeadingWhitespace = true; - params.trimTrailingSpaces = false; - params.chomp = CLIP; - params.onDocIndicator = THROW; - - // insert a potential simple key - if(m_simpleKeyAllowed) - InsertSimpleKey(); - - int line = INPUT.line, column = INPUT.column; - scalar = ScanScalar(INPUT, params); - m_simpleKeyAllowed = false; - - Token token(TT_SCALAR, line, column); - token.value = scalar; - m_tokens.push(token); - } - - // BlockScalarToken - // . These need a little extra processing beforehand. - // . We need to scan the line where the indicator is (this doesn't count as part of the scalar), - // and then we need to figure out what level of indentation we'll be using. - void Scanner::ScanBlockScalar() - { - std::string scalar; - - ScanScalarParams params; - params.indent = 1; - params.detectIndent = true; - - // eat block indicator ('|' or '>') - int line = INPUT.line, column = INPUT.column; - char indicator = INPUT.get(); - params.fold = (indicator == Keys::FoldedScalar); - - // eat chomping/indentation indicators - int n = Exp::Chomp.Match(INPUT); - for(int i=0;i= 0) - params.indent += m_indents.top(); - - params.eatLeadingWhitespace = false; - params.trimTrailingSpaces = false; - params.onTabInIndentation = THROW; - - scalar = ScanScalar(INPUT, params); - - // simple keys always ok after block scalars (since we're gonna start a new line anyways) - m_simpleKeyAllowed = true; - - Token token(TT_SCALAR, line, column); - token.value = scalar; - m_tokens.push(token); - } -} +#include "crt.h" +#include "scanner.h" +#include "token.h" +#include "exceptions.h" +#include "exp.h" +#include "scanscalar.h" +#include + +namespace YAML +{ + /////////////////////////////////////////////////////////////////////// + // Specialization for scanning specific tokens + + // Directive + // . Note: no semantic checking is done here (that's for the parser to do) + void Scanner::ScanDirective() + { + std::string name; + std::vector params; + + // pop indents and simple keys + PopIndentTo(-1); + VerifyAllSimpleKeys(); + + m_simpleKeyAllowed = false; + + // store pos and eat indicator + int line = INPUT.line, column = INPUT.column; + INPUT.eat(1); + + // read name + while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT)) + name += INPUT.get(); + + // read parameters + while(1) { + // first get rid of whitespace + while(Exp::Blank.Matches(INPUT)) + INPUT.eat(1); + + // break on newline or comment + if(INPUT.peek() == EOF || Exp::Break.Matches(INPUT) || Exp::Comment.Matches(INPUT)) + break; + + // now read parameter + std::string param; + while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT)) + param += INPUT.get(); + + params.push_back(param); + } + + Token token(TT_DIRECTIVE, line, column); + token.value = name; + token.params = params; + m_tokens.push(token); + } + + // DocStart + void Scanner::ScanDocStart() + { + PopIndentTo(INPUT.column); + VerifyAllSimpleKeys(); + m_simpleKeyAllowed = false; + + // eat + int line = INPUT.line, column = INPUT.column; + INPUT.eat(3); + m_tokens.push(Token(TT_DOC_START, line, column)); + } + + // DocEnd + void Scanner::ScanDocEnd() + { + PopIndentTo(-1); + VerifyAllSimpleKeys(); + m_simpleKeyAllowed = false; + + // eat + int line = INPUT.line, column = INPUT.column; + INPUT.eat(3); + m_tokens.push(Token(TT_DOC_END, line, column)); + } + + // FlowStart + void Scanner::ScanFlowStart() + { + // flows can be simple keys + InsertSimpleKey(); + m_flowLevel++; + m_simpleKeyAllowed = true; + + // eat + int line = INPUT.line, column = INPUT.column; + char ch = INPUT.get(); + TOKEN_TYPE type = (ch == Keys::FlowSeqStart ? TT_FLOW_SEQ_START : TT_FLOW_MAP_START); + m_tokens.push(Token(type, line, column)); + } + + // FlowEnd + void Scanner::ScanFlowEnd() + { + if(m_flowLevel == 0) + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::FLOW_END); + + m_flowLevel--; + m_simpleKeyAllowed = false; + + // eat + int line = INPUT.line, column = INPUT.column; + char ch = INPUT.get(); + TOKEN_TYPE type = (ch == Keys::FlowSeqEnd ? TT_FLOW_SEQ_END : TT_FLOW_MAP_END); + m_tokens.push(Token(type, line, column)); + } + + // FlowEntry + void Scanner::ScanFlowEntry() + { + m_simpleKeyAllowed = true; + + // eat + int line = INPUT.line, column = INPUT.column; + INPUT.eat(1); + m_tokens.push(Token(TT_FLOW_ENTRY, line, column)); + } + + // BlockEntry + void Scanner::ScanBlockEntry() + { + // we better be in the block context! + if(m_flowLevel > 0) + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::BLOCK_ENTRY); + + // can we put it here? + if(!m_simpleKeyAllowed) + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::BLOCK_ENTRY); + + PushIndentTo(INPUT.column, true); + m_simpleKeyAllowed = true; + + // eat + int line = INPUT.line, column = INPUT.column; + INPUT.eat(1); + m_tokens.push(Token(TT_BLOCK_ENTRY, line, column)); + } + + // Key + void Scanner::ScanKey() + { + // handle keys diffently in the block context (and manage indents) + if(m_flowLevel == 0) { + if(!m_simpleKeyAllowed) + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::MAP_KEY); + + PushIndentTo(INPUT.column, false); + } + + // can only put a simple key here if we're in block context + if(m_flowLevel == 0) + m_simpleKeyAllowed = true; + else + m_simpleKeyAllowed = false; + + // eat + int line = INPUT.line, column = INPUT.column; + INPUT.eat(1); + m_tokens.push(Token(TT_KEY, line, column)); + } + + // Value + void Scanner::ScanValue() + { + // does this follow a simple key? + if(m_isLastKeyValid) { + // can't follow a simple key with another simple key (dunno why, though - it seems fine) + m_simpleKeyAllowed = false; + } else { + // handle values diffently in the block context (and manage indents) + if(m_flowLevel == 0) { + if(!m_simpleKeyAllowed) + throw ParserException(INPUT.line, INPUT.column, ErrorMsg::MAP_VALUE); + + PushIndentTo(INPUT.column, false); + } + + // can only put a simple key here if we're in block context + if(m_flowLevel == 0) + m_simpleKeyAllowed = true; + else + m_simpleKeyAllowed = false; + } + + // eat + int line = INPUT.line, column = INPUT.column; + INPUT.eat(1); + m_tokens.push(Token(TT_VALUE, line, column)); + } + + // AnchorOrAlias + void Scanner::ScanAnchorOrAlias() + { + bool alias; + std::string name; + + // insert a potential simple key + if(m_simpleKeyAllowed) + InsertSimpleKey(); + m_simpleKeyAllowed = false; + + // eat the indicator + int line = INPUT.line, column = INPUT.column; + char indicator = INPUT.get(); + alias = (indicator == Keys::Alias); + + // now eat the content + while(Exp::AlphaNumeric.Matches(INPUT)) + name += INPUT.get(); + + // we need to have read SOMETHING! + if(name.empty()) + throw ParserException(INPUT.line, INPUT.column, alias ? ErrorMsg::ALIAS_NOT_FOUND : ErrorMsg::ANCHOR_NOT_FOUND); + + // and needs to end correctly + if(INPUT.peek() != EOF && !Exp::AnchorEnd.Matches(INPUT)) + throw ParserException(INPUT.line, INPUT.column, alias ? ErrorMsg::CHAR_IN_ALIAS : ErrorMsg::CHAR_IN_ANCHOR); + + // and we're done + Token token(alias ? TT_ALIAS : TT_ANCHOR, line, column); + token.value = name; + m_tokens.push(token); + } + + // Tag + void Scanner::ScanTag() + { + std::string handle, suffix; + + // insert a potential simple key + if(m_simpleKeyAllowed) + InsertSimpleKey(); + m_simpleKeyAllowed = false; + + // eat the indicator + int line = INPUT.line, column = INPUT.column; + handle += INPUT.get(); + + // read the handle + while(INPUT.peek() != EOF && INPUT.peek() != Keys::Tag && !Exp::BlankOrBreak.Matches(INPUT)) + handle += INPUT.get(); + + // is there a suffix? + if(INPUT.peek() == Keys::Tag) { + // eat the indicator + handle += INPUT.get(); + + // then read it + while(INPUT.peek() != EOF && !Exp::BlankOrBreak.Matches(INPUT)) + suffix += INPUT.get(); + } else { + // this is a bit weird: we keep just the '!' as the handle and move the rest to the suffix + suffix = handle.substr(1); + handle = "!"; + } + + Token token(TT_TAG, line, column); + token.value = handle; + token.params.push_back(suffix); + m_tokens.push(token); + } + + // PlainScalar + void Scanner::ScanPlainScalar() + { + std::string scalar; + + // set up the scanning parameters + ScanScalarParams params; + params.end = (m_flowLevel > 0 ? Exp::EndScalarInFlow : Exp::EndScalar) || (Exp::BlankOrBreak + Exp::Comment); + params.eatEnd = false; + params.indent = (m_flowLevel > 0 ? 0 : m_indents.top() + 1); + params.fold = true; + params.eatLeadingWhitespace = true; + params.trimTrailingSpaces = true; + params.chomp = CLIP; + params.onDocIndicator = BREAK; + params.onTabInIndentation = THROW; + + // insert a potential simple key + if(m_simpleKeyAllowed) + InsertSimpleKey(); + + int line = INPUT.line, column = INPUT.column; + scalar = ScanScalar(INPUT, params); + + // can have a simple key only if we ended the scalar by starting a new line + m_simpleKeyAllowed = params.leadingSpaces; + + // finally, check and see if we ended on an illegal character + //if(Exp::IllegalCharInScalar.Matches(INPUT)) + // throw ParserException(INPUT.line, INPUT.column, ErrorMsg::CHAR_IN_SCALAR); + + Token token(TT_SCALAR, line, column); + token.value = scalar; + m_tokens.push(token); + } + + // QuotedScalar + void Scanner::ScanQuotedScalar() + { + std::string scalar; + + // eat single or double quote + char quote = INPUT.get(); + bool single = (quote == '\''); + + // setup the scanning parameters + ScanScalarParams params; + params.end = (single ? RegEx(quote) && !Exp::EscSingleQuote : RegEx(quote)); + params.eatEnd = true; + params.escape = (single ? '\'' : '\\'); + params.indent = 0; + params.fold = true; + params.eatLeadingWhitespace = true; + params.trimTrailingSpaces = false; + params.chomp = CLIP; + params.onDocIndicator = THROW; + + // insert a potential simple key + if(m_simpleKeyAllowed) + InsertSimpleKey(); + + int line = INPUT.line, column = INPUT.column; + scalar = ScanScalar(INPUT, params); + m_simpleKeyAllowed = false; + + Token token(TT_SCALAR, line, column); + token.value = scalar; + m_tokens.push(token); + } + + // BlockScalarToken + // . These need a little extra processing beforehand. + // . We need to scan the line where the indicator is (this doesn't count as part of the scalar), + // and then we need to figure out what level of indentation we'll be using. + void Scanner::ScanBlockScalar() + { + std::string scalar; + + ScanScalarParams params; + params.indent = 1; + params.detectIndent = true; + + // eat block indicator ('|' or '>') + int line = INPUT.line, column = INPUT.column; + char indicator = INPUT.get(); + params.fold = (indicator == Keys::FoldedScalar); + + // eat chomping/indentation indicators + int n = Exp::Chomp.Match(INPUT); + for(int i=0;i= 0) + params.indent += m_indents.top(); + + params.eatLeadingWhitespace = false; + params.trimTrailingSpaces = false; + params.onTabInIndentation = THROW; + + scalar = ScanScalar(INPUT, params); + + // simple keys always ok after block scalars (since we're gonna start a new line anyways) + m_simpleKeyAllowed = true; + + Token token(TT_SCALAR, line, column); + token.value = scalar; + m_tokens.push(token); + } +} diff --git a/src/sequence.cpp b/src/sequence.cpp index f997a79..df4a201 100644 --- a/src/sequence.cpp +++ b/src/sequence.cpp @@ -1,175 +1,175 @@ -#include "crt.h" -#include "sequence.h" -#include "node.h" -#include "scanner.h" -#include "token.h" -#include - -namespace YAML -{ - Sequence::Sequence() - { - - } - - Sequence::~Sequence() - { - Clear(); - } - - void Sequence::Clear() - { - for(unsigned i=0;i::const_iterator& it) const - { - it = m_data.begin(); - return true; - } - - bool Sequence::GetEnd(std::vector ::const_iterator& it) const - { - it = m_data.end(); - return true; - } - - Node *Sequence::GetNode(unsigned i) const - { - if(i < m_data.size()) - return m_data[i]; - return 0; - } - - unsigned Sequence::GetSize() const - { - return m_data.size(); - } - - void Sequence::Parse(Scanner *pScanner, const ParserState& state) - { - Clear(); - - // split based on start token - switch(pScanner->peek().type) { - case TT_BLOCK_SEQ_START: ParseBlock(pScanner, state); break; - case TT_BLOCK_ENTRY: ParseImplicit(pScanner, state); break; - case TT_FLOW_SEQ_START: ParseFlow(pScanner, state); break; - } - } - - void Sequence::ParseBlock(Scanner *pScanner, const ParserState& state) - { - // eat start token - pScanner->pop(); - - while(1) { - if(pScanner->empty()) - throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ); - - Token token = pScanner->peek(); - if(token.type != TT_BLOCK_ENTRY && token.type != TT_BLOCK_END) - throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ); - - pScanner->pop(); - if(token.type == TT_BLOCK_END) - break; - - Node *pNode = new Node; - m_data.push_back(pNode); - pNode->Parse(pScanner, state); - } - } - - void Sequence::ParseImplicit(Scanner *pScanner, const ParserState& state) - { - while(1) { - // we're actually *allowed* to have no tokens at some point - if(pScanner->empty()) - break; - - // and we end at anything other than a block entry - Token& token = pScanner->peek(); - if(token.type != TT_BLOCK_ENTRY) - break; - - pScanner->pop(); - - Node *pNode = new Node; - m_data.push_back(pNode); - pNode->Parse(pScanner, state); - } - } - - void Sequence::ParseFlow(Scanner *pScanner, const ParserState& state) - { - // eat start token - pScanner->pop(); - - while(1) { - if(pScanner->empty()) - throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ_FLOW); - - // first check for end - if(pScanner->peek().type == TT_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 == TT_FLOW_ENTRY) - pScanner->pop(); - else if(token.type != TT_FLOW_SEQ_END) - throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ_FLOW); - } - } - - void Sequence::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) - { - if(startedLine && !onlyOneCharOnLine) - out << "\n"; - - for(unsigned i=0;i 0) { - for(int j=0;jWrite(out, indent + 1, true, i > 0 || !startedLine || onlyOneCharOnLine); - } - - if(m_data.empty()) - out << "\n"; - } - - int Sequence::Compare(Content *pContent) - { - return -pContent->Compare(this); - } - - int Sequence::Compare(Sequence *pSeq) - { - unsigned n = m_data.size(), m = pSeq->m_data.size(); - if(n < m) - return -1; - else if(n > m) - return 1; - - for(unsigned i=0;iCompare(*pSeq->m_data[i]); - if(cmp != 0) - return cmp; - } - - return 0; - } -} +#include "crt.h" +#include "sequence.h" +#include "node.h" +#include "scanner.h" +#include "token.h" +#include + +namespace YAML +{ + Sequence::Sequence() + { + + } + + Sequence::~Sequence() + { + Clear(); + } + + void Sequence::Clear() + { + for(unsigned i=0;i::const_iterator& it) const + { + it = m_data.begin(); + return true; + } + + bool Sequence::GetEnd(std::vector ::const_iterator& it) const + { + it = m_data.end(); + return true; + } + + Node *Sequence::GetNode(unsigned i) const + { + if(i < m_data.size()) + return m_data[i]; + return 0; + } + + unsigned Sequence::GetSize() const + { + return m_data.size(); + } + + void Sequence::Parse(Scanner *pScanner, const ParserState& state) + { + Clear(); + + // split based on start token + switch(pScanner->peek().type) { + case TT_BLOCK_SEQ_START: ParseBlock(pScanner, state); break; + case TT_BLOCK_ENTRY: ParseImplicit(pScanner, state); break; + case TT_FLOW_SEQ_START: ParseFlow(pScanner, state); break; + } + } + + void Sequence::ParseBlock(Scanner *pScanner, const ParserState& state) + { + // eat start token + pScanner->pop(); + + while(1) { + if(pScanner->empty()) + throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ); + + Token token = pScanner->peek(); + if(token.type != TT_BLOCK_ENTRY && token.type != TT_BLOCK_END) + throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ); + + pScanner->pop(); + if(token.type == TT_BLOCK_END) + break; + + Node *pNode = new Node; + m_data.push_back(pNode); + pNode->Parse(pScanner, state); + } + } + + void Sequence::ParseImplicit(Scanner *pScanner, const ParserState& state) + { + while(1) { + // we're actually *allowed* to have no tokens at some point + if(pScanner->empty()) + break; + + // and we end at anything other than a block entry + Token& token = pScanner->peek(); + if(token.type != TT_BLOCK_ENTRY) + break; + + pScanner->pop(); + + Node *pNode = new Node; + m_data.push_back(pNode); + pNode->Parse(pScanner, state); + } + } + + void Sequence::ParseFlow(Scanner *pScanner, const ParserState& state) + { + // eat start token + pScanner->pop(); + + while(1) { + if(pScanner->empty()) + throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ_FLOW); + + // first check for end + if(pScanner->peek().type == TT_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 == TT_FLOW_ENTRY) + pScanner->pop(); + else if(token.type != TT_FLOW_SEQ_END) + throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ_FLOW); + } + } + + void Sequence::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) + { + if(startedLine && !onlyOneCharOnLine) + out << "\n"; + + for(unsigned i=0;i 0) { + for(int j=0;jWrite(out, indent + 1, true, i > 0 || !startedLine || onlyOneCharOnLine); + } + + if(m_data.empty()) + out << "\n"; + } + + int Sequence::Compare(Content *pContent) + { + return -pContent->Compare(this); + } + + int Sequence::Compare(Sequence *pSeq) + { + unsigned n = m_data.size(), m = pSeq->m_data.size(); + if(n < m) + return -1; + else if(n > m) + return 1; + + for(unsigned i=0;iCompare(*pSeq->m_data[i]); + if(cmp != 0) + return cmp; + } + + return 0; + } +} diff --git a/src/sequence.h b/src/sequence.h index 89dba85..6d5b01c 100644 --- a/src/sequence.h +++ b/src/sequence.h @@ -1,41 +1,41 @@ -#pragma once - -#include "content.h" -#include - -namespace YAML -{ - class Node; - - class Sequence: public Content - { - public: - Sequence(); - virtual ~Sequence(); - - void Clear(); - virtual bool GetBegin(std::vector ::const_iterator& it) const; - virtual bool GetEnd(std::vector ::const_iterator& it) const; - virtual Node *GetNode(unsigned i) const; - virtual unsigned GetSize() const; - - virtual void Parse(Scanner *pScanner, const ParserState& state); - virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); - - virtual bool IsSequence() const { return true; } - - // ordering - virtual int Compare(Content *pContent); - virtual int Compare(Scalar *pScalar) { return 1; } - virtual int Compare(Sequence *pSeq); - virtual int Compare(Map *pMap) { return -1; } - - private: - void ParseBlock(Scanner *pScanner, const ParserState& state); - void ParseImplicit(Scanner *pScanner, const ParserState& state); - void ParseFlow(Scanner *pScanner, const ParserState& state); - - protected: - std::vector m_data; - }; -} +#pragma once + +#include "content.h" +#include + +namespace YAML +{ + class Node; + + class Sequence: public Content + { + public: + Sequence(); + virtual ~Sequence(); + + void Clear(); + virtual bool GetBegin(std::vector ::const_iterator& it) const; + virtual bool GetEnd(std::vector ::const_iterator& it) const; + virtual Node *GetNode(unsigned i) const; + virtual unsigned GetSize() const; + + virtual void Parse(Scanner *pScanner, const ParserState& state); + virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); + + virtual bool IsSequence() const { return true; } + + // ordering + virtual int Compare(Content *pContent); + virtual int Compare(Scalar *pScalar) { return 1; } + virtual int Compare(Sequence *pSeq); + virtual int Compare(Map *pMap) { return -1; } + + private: + void ParseBlock(Scanner *pScanner, const ParserState& state); + void ParseImplicit(Scanner *pScanner, const ParserState& state); + void ParseFlow(Scanner *pScanner, const ParserState& state); + + protected: + std::vector m_data; + }; +} diff --git a/src/simplekey.cpp b/src/simplekey.cpp index e9d25ee..32a1761 100644 --- a/src/simplekey.cpp +++ b/src/simplekey.cpp @@ -1,102 +1,102 @@ -#include "crt.h" -#include "scanner.h" -#include "token.h" -#include "exceptions.h" -#include "exp.h" - -namespace YAML -{ - Scanner::SimpleKey::SimpleKey(int pos_, int line_, int column_, int flowLevel_) - : pos(pos_), line(line_), column(column_), flowLevel(flowLevel_), pMapStart(0), pKey(0) - { - } - - void Scanner::SimpleKey::Validate() - { - if(pMapStart) - pMapStart->status = TS_VALID; - if(pKey) - pKey->status = TS_VALID; - } - - void Scanner::SimpleKey::Invalidate() - { - if(pMapStart) - pMapStart->status = TS_INVALID; - if(pKey) - pKey->status = TS_INVALID; - } - - // InsertSimpleKey - // . Adds a potential simple key to the queue, - // and saves it on a stack. - void Scanner::InsertSimpleKey() - { - SimpleKey key(INPUT.pos(), INPUT.line, INPUT.column, m_flowLevel); - - // first add a map start, if necessary - key.pMapStart = PushIndentTo(INPUT.column, false); - if(key.pMapStart) - key.pMapStart->status = TS_UNVERIFIED; - - // then add the (now unverified) key - m_tokens.push(Token(TT_KEY, INPUT.line, INPUT.column)); - key.pKey = &m_tokens.back(); - key.pKey->status = TS_UNVERIFIED; - - m_simpleKeys.push(key); - } - - // VerifySimpleKey - // . Determines whether the latest simple key to be added is valid, - // and if so, makes it valid. - bool Scanner::VerifySimpleKey() - { - m_isLastKeyValid = false; - if(m_simpleKeys.empty()) - return m_isLastKeyValid; - - // grab top key - SimpleKey key = m_simpleKeys.top(); - - // only validate if we're in the correct flow level - if(key.flowLevel != m_flowLevel) - return false; - - m_simpleKeys.pop(); - - bool isValid = true; - - // needs to be followed immediately by a value - if(m_flowLevel > 0 && !Exp::ValueInFlow.Matches(INPUT)) - isValid = false; - if(m_flowLevel == 0 && !Exp::Value.Matches(INPUT)) - isValid = false; - - // also needs to be less than 1024 characters and inline - if(INPUT.line != key.line || INPUT.pos() - key.pos > 1024) - isValid = false; - - // invalidate key - if(isValid) - key.Validate(); - else - key.Invalidate(); - - // In block style, remember that we've pushed an indent for this potential simple key (if it was starting). - // If it was invalid, then we need to pop it off. - // Note: we're guaranteed to be popping the right one (i.e., there couldn't have been anything in - // between) since keys have to be inline, and will be invalidated immediately on a newline. - if(!isValid && m_flowLevel == 0) - m_indents.pop(); - - m_isLastKeyValid = isValid; - return isValid; - } - - void Scanner::VerifyAllSimpleKeys() - { - while(!m_simpleKeys.empty()) - VerifySimpleKey(); - } -} +#include "crt.h" +#include "scanner.h" +#include "token.h" +#include "exceptions.h" +#include "exp.h" + +namespace YAML +{ + Scanner::SimpleKey::SimpleKey(int pos_, int line_, int column_, int flowLevel_) + : pos(pos_), line(line_), column(column_), flowLevel(flowLevel_), pMapStart(0), pKey(0) + { + } + + void Scanner::SimpleKey::Validate() + { + if(pMapStart) + pMapStart->status = TS_VALID; + if(pKey) + pKey->status = TS_VALID; + } + + void Scanner::SimpleKey::Invalidate() + { + if(pMapStart) + pMapStart->status = TS_INVALID; + if(pKey) + pKey->status = TS_INVALID; + } + + // InsertSimpleKey + // . Adds a potential simple key to the queue, + // and saves it on a stack. + void Scanner::InsertSimpleKey() + { + SimpleKey key(INPUT.pos(), INPUT.line, INPUT.column, m_flowLevel); + + // first add a map start, if necessary + key.pMapStart = PushIndentTo(INPUT.column, false); + if(key.pMapStart) + key.pMapStart->status = TS_UNVERIFIED; + + // then add the (now unverified) key + m_tokens.push(Token(TT_KEY, INPUT.line, INPUT.column)); + key.pKey = &m_tokens.back(); + key.pKey->status = TS_UNVERIFIED; + + m_simpleKeys.push(key); + } + + // VerifySimpleKey + // . Determines whether the latest simple key to be added is valid, + // and if so, makes it valid. + bool Scanner::VerifySimpleKey() + { + m_isLastKeyValid = false; + if(m_simpleKeys.empty()) + return m_isLastKeyValid; + + // grab top key + SimpleKey key = m_simpleKeys.top(); + + // only validate if we're in the correct flow level + if(key.flowLevel != m_flowLevel) + return false; + + m_simpleKeys.pop(); + + bool isValid = true; + + // needs to be followed immediately by a value + if(m_flowLevel > 0 && !Exp::ValueInFlow.Matches(INPUT)) + isValid = false; + if(m_flowLevel == 0 && !Exp::Value.Matches(INPUT)) + isValid = false; + + // also needs to be less than 1024 characters and inline + if(INPUT.line != key.line || INPUT.pos() - key.pos > 1024) + isValid = false; + + // invalidate key + if(isValid) + key.Validate(); + else + key.Invalidate(); + + // In block style, remember that we've pushed an indent for this potential simple key (if it was starting). + // If it was invalid, then we need to pop it off. + // Note: we're guaranteed to be popping the right one (i.e., there couldn't have been anything in + // between) since keys have to be inline, and will be invalidated immediately on a newline. + if(!isValid && m_flowLevel == 0) + m_indents.pop(); + + m_isLastKeyValid = isValid; + return isValid; + } + + void Scanner::VerifyAllSimpleKeys() + { + while(!m_simpleKeys.empty()) + VerifySimpleKey(); + } +} diff --git a/src/stream.cpp b/src/stream.cpp index 73d4129..b388899 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -1,53 +1,53 @@ -#include "crt.h" -#include "stream.h" -#include - -namespace YAML -{ - int Stream::pos() const - { - return input.tellg(); - } - - char Stream::peek() - { - return input.peek(); - } - - Stream::operator bool() - { - return input.good(); - } - - // get - // . Extracts a character from the stream and updates our position - char Stream::get() - { - char ch = input.get(); - column++; - if(ch == '\n') { - column = 0; - line++; - } - return ch; - } - - // get - // . Extracts 'n' characters from the stream and updates our position - std::string Stream::get(int n) - { - std::string ret; - for(int i=0;i + +namespace YAML +{ + int Stream::pos() const + { + return input.tellg(); + } + + char Stream::peek() + { + return input.peek(); + } + + Stream::operator bool() + { + return input.good(); + } + + // get + // . Extracts a character from the stream and updates our position + char Stream::get() + { + char ch = input.get(); + column++; + if(ch == '\n') { + column = 0; + line++; + } + return ch; + } + + // get + // . Extracts 'n' characters from the stream and updates our position + std::string Stream::get(int n) + { + std::string ret; + for(int i=0;i -#include - -namespace YAML -{ - struct Stream - { - Stream(std::istream& input_): input(input_), line(0), column(0) {} - - int pos() const; - operator bool(); - bool operator !() { return !(*this); } - - std::istream& stream() const { return input; } - char peek(); - char get(); - std::string get(int n); - void eat(int n = 1); - - std::istream& input; - int line, column; - }; -} +#pragma once + +#include +#include + +namespace YAML +{ + struct Stream + { + Stream(std::istream& input_): input(input_), line(0), column(0) {} + + int pos() const; + operator bool(); + bool operator !() { return !(*this); } + + std::istream& stream() const { return input; } + char peek(); + char get(); + std::string get(int n); + void eat(int n = 1); + + std::istream& input; + int line, column; + }; +} diff --git a/src/token.h b/src/token.h index 8a98c1a..5b000d1 100644 --- a/src/token.h +++ b/src/token.h @@ -1,68 +1,68 @@ -#pragma once - -#include -#include -#include - -namespace YAML -{ - enum TOKEN_STATUS { TS_VALID, TS_INVALID, TS_UNVERIFIED }; - enum TOKEN_TYPE { - TT_DIRECTIVE, - TT_DOC_START, - TT_DOC_END, - TT_BLOCK_SEQ_START, - TT_BLOCK_MAP_START, - TT_BLOCK_END, - TT_BLOCK_ENTRY, - TT_FLOW_SEQ_START, - TT_FLOW_MAP_START, - TT_FLOW_SEQ_END, - TT_FLOW_MAP_END, - TT_FLOW_ENTRY, - TT_KEY, - TT_VALUE, - TT_ANCHOR, - TT_ALIAS, - TT_TAG, - TT_SCALAR, - }; - - const std::string TokenNames[] = { - "DIRECTIVE", - "DOC_START", - "DOC_END", - "BLOCK_SEQ_START", - "BLOCK_MAP_START", - "BLOCK_END", - "BLOCK_ENTRY", - "FLOW_SEQ_START", - "FLOW_MAP_START", - "FLOW_SEQ_END", - "FLOW_MAP_END", - "FLOW_ENTRY", - "KEY", - "VALUE", - "ANCHOR", - "ALIAS", - "TAG", - "SCALAR", - }; - - struct Token { - Token(TOKEN_TYPE type_, int line_, int column_): status(TS_VALID), type(type_), line(line_), column(column_) {} - - friend std::ostream& operator << (std::ostream& out, const Token& token) { - out << TokenNames[token.type] << std::string(": ") << token.value; - for(unsigned i=0;i params; - }; -} +#pragma once + +#include +#include +#include + +namespace YAML +{ + enum TOKEN_STATUS { TS_VALID, TS_INVALID, TS_UNVERIFIED }; + enum TOKEN_TYPE { + TT_DIRECTIVE, + TT_DOC_START, + TT_DOC_END, + TT_BLOCK_SEQ_START, + TT_BLOCK_MAP_START, + TT_BLOCK_END, + TT_BLOCK_ENTRY, + TT_FLOW_SEQ_START, + TT_FLOW_MAP_START, + TT_FLOW_SEQ_END, + TT_FLOW_MAP_END, + TT_FLOW_ENTRY, + TT_KEY, + TT_VALUE, + TT_ANCHOR, + TT_ALIAS, + TT_TAG, + TT_SCALAR, + }; + + const std::string TokenNames[] = { + "DIRECTIVE", + "DOC_START", + "DOC_END", + "BLOCK_SEQ_START", + "BLOCK_MAP_START", + "BLOCK_END", + "BLOCK_ENTRY", + "FLOW_SEQ_START", + "FLOW_MAP_START", + "FLOW_SEQ_END", + "FLOW_MAP_END", + "FLOW_ENTRY", + "KEY", + "VALUE", + "ANCHOR", + "ALIAS", + "TAG", + "SCALAR", + }; + + struct Token { + Token(TOKEN_TYPE type_, int line_, int column_): status(TS_VALID), type(type_), line(line_), column(column_) {} + + friend std::ostream& operator << (std::ostream& out, const Token& token) { + out << TokenNames[token.type] << std::string(": ") << token.value; + for(unsigned i=0;i params; + }; +} diff --git a/yaml-reader/main.cpp b/yaml-reader/main.cpp index 1d32cba..ab122c0 100644 --- a/yaml-reader/main.cpp +++ b/yaml-reader/main.cpp @@ -1,41 +1,41 @@ -#include "yaml.h" -#include "tests.h" -#include -#include - -#ifdef _MSC_VER -#ifdef _DEBUG -#pragma comment(lib, "yamlcppd.lib") -#else -#pragma comment(lib, "yamlcpp.lib") -#endif // _DEBUG -#endif // _MSC_VER - -void run() -{ - std::ifstream fin("tests/test.yaml"); - - try { - YAML::Parser parser(fin); - parser.PrintTokens(std::cout); - } catch(YAML::Exception&) { - std::cout << "Error parsing the yaml!\n"; - } -} - -int main(int argc, char **argv) -{ - bool verbose = false; - for(int i=1;i +#include + +#ifdef _MSC_VER +#ifdef _DEBUG +#pragma comment(lib, "yamlcppd.lib") +#else +#pragma comment(lib, "yamlcpp.lib") +#endif // _DEBUG +#endif // _MSC_VER + +void run() +{ + std::ifstream fin("tests/test.yaml"); + + try { + YAML::Parser parser(fin); + parser.PrintTokens(std::cout); + } catch(YAML::Exception&) { + std::cout << "Error parsing the yaml!\n"; + } +} + +int main(int argc, char **argv) +{ + bool verbose = false; + for(int i=1;i -#include -#include -#include - -namespace Test -{ - // runs all the tests on all data we have - void RunAll(bool verbose) - { - std::vector files; - files.push_back("tests/simple.yaml"); - files.push_back("tests/mixed.yaml"); - files.push_back("tests/scalars.yaml"); - files.push_back("tests/directives.yaml"); - - bool passed = true; - for(unsigned i=0;i +#include +#include +#include + +namespace Test +{ + // runs all the tests on all data we have + void RunAll(bool verbose) + { + std::vector files; + files.push_back("tests/simple.yaml"); + files.push_back("tests/mixed.yaml"); + files.push_back("tests/scalars.yaml"); + files.push_back("tests/directives.yaml"); + + bool passed = true; + for(unsigned i=0;i - -namespace Test { - void RunAll(bool verbose); - bool Inout(const std::string& file, bool verbose); -} +#include + +namespace Test { + void RunAll(bool verbose); + bool Inout(const std::string& file, bool verbose); +} diff --git a/yaml-reader/tests/directives.yaml b/yaml-reader/tests/directives.yaml index ff09846..adc9130 100644 --- a/yaml-reader/tests/directives.yaml +++ b/yaml-reader/tests/directives.yaml @@ -1,5 +1,5 @@ -%YAML 1.2 -%TAG ! !howdy ---- -- basic node +%YAML 1.2 +%TAG ! !howdy +--- +- basic node - ! yeah baby \ No newline at end of file diff --git a/yaml-reader/tests/mixed.yaml b/yaml-reader/tests/mixed.yaml index 88da1e7..68cbf4a 100644 --- a/yaml-reader/tests/mixed.yaml +++ b/yaml-reader/tests/mixed.yaml @@ -1,32 +1,32 @@ -- the main thing is a sequence -- here's a key: value - and another: value -- let's inline: [1, 2, 3] - and an inline map: {key: value, 243: 101} -- and multiple indents: - - here's - - a - - list - and another: - - list - - of - - things -- maybe now: - let's: get - pretty: - deep: here - in: - the: nesting - just: to - confuse: - the: heck - out: - - of - - the: parser - if: - - we - - can - - do: that - what: do - you: think? +- the main thing is a sequence +- here's a key: value + and another: value +- let's inline: [1, 2, 3] + and an inline map: {key: value, 243: 101} +- and multiple indents: + - here's + - a + - list + and another: + - list + - of + - things +- maybe now: + let's: get + pretty: + deep: here + in: + the: nesting + just: to + confuse: + the: heck + out: + - of + - the: parser + if: + - we + - can + - do: that + what: do + you: think? \ No newline at end of file diff --git a/yaml-reader/tests/scalars.yaml b/yaml-reader/tests/scalars.yaml index ae0059a..65f9a06 100644 --- a/yaml-reader/tests/scalars.yaml +++ b/yaml-reader/tests/scalars.yaml @@ -1,35 +1,35 @@ -- normal scalar, but - over several lines -- | - literal scalar - so we can draw ASCII: - - - - - | - | - ------ -- > - and a folded scalar... so we - can just keep writing various - things. And if we want to keep indentation: - - we just indent a little - see, this stays indented -- >- - Here's a folded scalar - that gets chomped. -- |- - And here's a literal scalar - that gets chomped. -- >2 - Here's a folded scalar - that starts with some indentation. -- ::vector -- ": - ()" -- Up, up, and away! -- -123 -- http://example.com/foo#bar -# Inside flow collection: -- [ ::vector, - ": - ()", - "Up, up and away!", - -123, +- normal scalar, but + over several lines +- | + literal scalar - so we can draw ASCII: + + - - + | - | + ------ +- > + and a folded scalar... so we + can just keep writing various + things. And if we want to keep indentation: + + we just indent a little + see, this stays indented +- >- + Here's a folded scalar + that gets chomped. +- |- + And here's a literal scalar + that gets chomped. +- >2 + Here's a folded scalar + that starts with some indentation. +- ::vector +- ": - ()" +- Up, up, and away! +- -123 +- http://example.com/foo#bar +# Inside flow collection: +- [ ::vector, + ": - ()", + "Up, up and away!", + -123, http://example.com/foo#bar ] \ No newline at end of file diff --git a/yaml-reader/tests/simple.yaml b/yaml-reader/tests/simple.yaml index 55b2d21..69d4239 100644 --- a/yaml-reader/tests/simple.yaml +++ b/yaml-reader/tests/simple.yaml @@ -1,13 +1,13 @@ ---- -just a scalar ---- -and another scalar ---- -now an end document -... ---- -and now two -... -... ---- +--- +just a scalar +--- +and another scalar +--- +now an end document +... +--- +and now two +... +... +--- and that's it \ No newline at end of file diff --git a/yaml-reader/tests/test.yaml b/yaml-reader/tests/test.yaml index 1392289..662ec0c 100644 --- a/yaml-reader/tests/test.yaml +++ b/yaml-reader/tests/test.yaml @@ -1,3 +1,3 @@ -- it's just -- one thing -- after another +- it's just +- one thing +- after another From c44b8e601efe7f022e9dc32d5f5793add7db66f2 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 11 Sep 2008 03:48:04 +0000 Subject: [PATCH 067/295] --- yaml-reader.vcproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index b864dc6..0d7cdda 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -45,7 +45,7 @@ BasicRuntimeChecks="3" RuntimeLibrary="3" WarningLevel="3" - DebugInformationFormat="4" + DebugInformationFormat="3" /> Date: Thu, 11 Sep 2008 03:49:52 +0000 Subject: [PATCH 068/295] --- yamlcpp.vcproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yamlcpp.vcproj b/yamlcpp.vcproj index 9e4fac3..ee5923c 100644 --- a/yamlcpp.vcproj +++ b/yamlcpp.vcproj @@ -48,7 +48,7 @@ RuntimeLibrary="3" UsePrecompiledHeader="0" WarningLevel="3" - DebugInformationFormat="4" + DebugInformationFormat="3" /> Date: Fri, 19 Sep 2008 02:44:49 +0000 Subject: [PATCH 069/295] Made Node non-copyable. --- include/node.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/node.h b/include/node.h index 8f1a739..0ac945c 100644 --- a/include/node.h +++ b/include/node.h @@ -78,6 +78,11 @@ namespace YAML int Compare(const Node& rhs) const; friend bool operator < (const Node& n1, const Node& n2); + private: + // shouldn't be copyable! (at least for now) + Node(const Node& rhs); + Node& operator = (const Node& rhs); + private: void ParseHeader(Scanner *pScanner, const ParserState& state); void ParseTag(Scanner *pScanner, const ParserState& state); From d51888bc7e101bf31efb042c7804ff89c6f0eb6c Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 23 Sep 2008 21:13:23 +0000 Subject: [PATCH 070/295] Fixed a problem where you lose the exception type on rethrow. --- src/map.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index facb537..89f5b70 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -80,10 +80,10 @@ namespace YAML } m_data[pKey] = pValue; - } catch(Exception& e) { + } catch(Exception&) { delete pKey; delete pValue; - throw e; + throw; } } } @@ -131,11 +131,11 @@ namespace YAML throw ParserException(nextToken.line, nextToken.column, ErrorMsg::END_OF_MAP_FLOW); m_data[pKey] = pValue; - } catch(Exception& e) { + } catch(Exception&) { // clean up and rethrow delete pKey; delete pValue; - throw e; + throw; } } } From ecba08e24027591668911b73d3dd67e40186574a Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 24 Sep 2008 22:45:04 +0000 Subject: [PATCH 071/295] Fixed infinite loop bug having to do with simple keys when we hit an unexpected EOF. --- src/scanner.h | 2 +- src/simplekey.cpp | 12 +++++++++--- yaml-reader/tests/test.yaml | 4 +--- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/scanner.h b/src/scanner.h index 8764719..e4590ef 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -33,7 +33,7 @@ namespace YAML // checking input void InsertSimpleKey(); - bool VerifySimpleKey(); + bool VerifySimpleKey(bool force = false); void VerifyAllSimpleKeys(); bool IsWhitespaceToBeEaten(char ch); diff --git a/src/simplekey.cpp b/src/simplekey.cpp index 32a1761..f971c54 100644 --- a/src/simplekey.cpp +++ b/src/simplekey.cpp @@ -50,7 +50,8 @@ namespace YAML // VerifySimpleKey // . Determines whether the latest simple key to be added is valid, // and if so, makes it valid. - bool Scanner::VerifySimpleKey() + // . If 'force' is true, then we'll pop no matter what (whether we can verify it or not). + bool Scanner::VerifySimpleKey(bool force) { m_isLastKeyValid = false; if(m_simpleKeys.empty()) @@ -60,8 +61,11 @@ namespace YAML SimpleKey key = m_simpleKeys.top(); // only validate if we're in the correct flow level - if(key.flowLevel != m_flowLevel) + if(key.flowLevel != m_flowLevel) { + if(force) + m_simpleKeys.pop(); return false; + } m_simpleKeys.pop(); @@ -94,9 +98,11 @@ namespace YAML return isValid; } + // VerifyAllSimplyKeys + // . Pops all simple keys (with checking, but if we can't verify one, then pop it anyways). void Scanner::VerifyAllSimpleKeys() { while(!m_simpleKeys.empty()) - VerifySimpleKey(); + VerifySimpleKey(true); } } diff --git a/yaml-reader/tests/test.yaml b/yaml-reader/tests/test.yaml index 662ec0c..6938c5c 100644 --- a/yaml-reader/tests/test.yaml +++ b/yaml-reader/tests/test.yaml @@ -1,3 +1 @@ -- it's just -- one thing -- after another +bad YAML: [ \ No newline at end of file From bf01059c38f16acfa3bff19ca473eefa4943d6e1 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 24 Sep 2008 23:29:00 +0000 Subject: [PATCH 072/295] Added Read() functions for Node that return true/false, so we can easily check if a read is successful without throwing. But we still have operator >> that throws on failure. --- include/node.h | 94 +++++++++++++++++++++++++++++++++----------------- src/content.h | 14 ++++---- src/node.cpp | 60 +++++++++++++++++--------------- src/scalar.cpp | 33 ++++++++---------- src/scalar.h | 14 ++++---- 5 files changed, 123 insertions(+), 92 deletions(-) diff --git a/include/node.h b/include/node.h index 0ac945c..f970f4f 100644 --- a/include/node.h +++ b/include/node.h @@ -32,45 +32,35 @@ namespace YAML Iterator end() const; unsigned size() const; + // extraction of scalars + bool Read(std::string& s) const; + bool Read(int& i) const; + bool Read(unsigned& u) const; + bool Read(long& l) const; + bool Read(float& f) const; + bool Read(double& d) const; + bool Read(char& c) const; + + // so you can specialize for other values template - const Node& GetValue(const T& key) const { - if(!m_pContent) - throw BadDereference(); - - for(Iterator it=begin();it!=end();++it) { - T t; - try { - it.first() >> t; - if(key == t) - return it.second(); - } catch(RepresentationException&) { - } - } - - throw BadDereference(); - } + friend bool Read(const Node& node, T& value); template - const Node& operator [] (const T& key) const { - return GetValue(key); - } + friend void operator >> (const Node& node, T& value); - const Node& operator [] (const char *key) const { - return GetValue(std::string(key)); - } + // just for maps + template + const Node& GetValue(const T& key) const; + template + const Node& operator [] (const T& key) const; + + const Node& operator [] (const char *key) const; + + // just for sequences const Node& operator [] (unsigned u) const; const Node& operator [] (int i) const; - // extraction - friend void operator >> (const Node& node, std::string& s); - friend void operator >> (const Node& node, int& i); - friend void operator >> (const Node& node, unsigned& u); - friend void operator >> (const Node& node, long& l); - friend void operator >> (const Node& node, float& f); - friend void operator >> (const Node& node, double& d); - friend void operator >> (const Node& node, char& c); - // insertion friend std::ostream& operator << (std::ostream& out, const Node& node); @@ -94,4 +84,46 @@ namespace YAML Content *m_pContent; bool m_alias; }; + + // templated things we need to keep inline in the header + template + inline bool Read(const Node& node, T& value) + { + return node.Read(value); + } + + template + inline void operator >> (const Node& node, T& value) + { + if(!Read(node, value)) + throw InvalidScalar(); + } + + template + inline const Node& Node::GetValue(const T& key) const + { + if(!m_pContent) + throw BadDereference(); + + for(Iterator it=begin();it!=end();++it) { + T t; + if(YAML::Read(it.first(), t)) { + if(key == t) + return it.second(); + } + } + + throw BadDereference(); + } + + template + inline const Node& Node::operator [] (const T& key) const + { + return GetValue(key); + } + + inline const Node& Node::operator [] (const char *key) const + { + return GetValue(std::string(key)); + } } diff --git a/src/content.h b/src/content.h index b7a5da9..9561a4b 100644 --- a/src/content.h +++ b/src/content.h @@ -36,13 +36,13 @@ namespace YAML virtual bool IsSequence() const { return false; } // extraction - virtual void Read(std::string& s) { throw InvalidScalar(); } - virtual void Read(int& i) { throw InvalidScalar(); } - virtual void Read(unsigned& u) { throw InvalidScalar(); } - virtual void Read(long& l) { throw InvalidScalar(); } - virtual void Read(float& f) { throw InvalidScalar(); } - virtual void Read(double& d) { throw InvalidScalar(); } - virtual void Read(char& c) { throw InvalidScalar(); } + virtual bool Read(std::string& s) const { return false; } + virtual bool Read(int& i) const { return false; } + virtual bool Read(unsigned& u) const { return false; } + virtual bool Read(long& l) const { return false; } + virtual bool Read(float& f) const { return false; } + virtual bool Read(double& d) const { return false; } + virtual bool Read(char& c) const { return false; } // ordering virtual int Compare(Content *pContent) { return 0; } diff --git a/src/node.cpp b/src/node.cpp index f009903..df79ad4 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -232,61 +232,65 @@ namespace YAML /////////////////////////////////////////////////////// // Extraction + // Note: these Read() functions are identical, but + // they're not templated because they use a Content virtual + // function, so we'd have to #include that in node.h, and + // I don't want to. - void operator >> (const Node& node, std::string& s) + bool Node::Read(std::string& s) const { - if(!node.m_pContent) - throw; + if(!m_pContent) + return false; - node.m_pContent->Read(s); + return m_pContent->Read(s); } - void operator >> (const Node& node, int& i) + bool Node::Read(int& i) const { - if(!node.m_pContent) - throw; + if(!m_pContent) + return false; - node.m_pContent->Read(i); + return m_pContent->Read(i); } - void operator >> (const Node& node, unsigned& u) + bool Node::Read(unsigned& u) const { - if(!node.m_pContent) - throw; + if(!m_pContent) + return false; - node.m_pContent->Read(u); + return m_pContent->Read(u); } - void operator >> (const Node& node, long& l) + bool Node::Read(long& l) const { - if(!node.m_pContent) - throw; + if(!m_pContent) + return false; - node.m_pContent->Read(l); + return m_pContent->Read(l); } - void operator >> (const Node& node, float& f) + bool Node::Read(float& f) const { - if(!node.m_pContent) - throw; + if(!m_pContent) + return false; - node.m_pContent->Read(f); + return m_pContent->Read(f); } - void operator >> (const Node& node, double& d) + bool Node::Read(double& d) const { - if(!node.m_pContent) - throw; + if(!m_pContent) + return false; - node.m_pContent->Read(d); + return m_pContent->Read(d); } - void operator >> (const Node& node, char& c) + bool Node::Read(char& c) const { - if(!node.m_pContent) - throw; + if(!m_pContent) + return false; - node.m_pContent->Read(c); + return m_pContent->Read(c); } std::ostream& operator << (std::ostream& out, const Node& node) diff --git a/src/scalar.cpp b/src/scalar.cpp index ed8f032..00985cb 100644 --- a/src/scalar.cpp +++ b/src/scalar.cpp @@ -38,57 +38,52 @@ namespace YAML out << "\"\n"; } - void Scalar::Read(std::string& s) + bool Scalar::Read(std::string& s) const { s = m_data; + return true; } - void Scalar::Read(int& i) + bool Scalar::Read(int& i) const { std::stringstream data(m_data); data >> i; - if(!data) - throw InvalidScalar(); + return !data.fail(); } - void Scalar::Read(unsigned& u) + bool Scalar::Read(unsigned& u) const { std::stringstream data(m_data); data >> u; - if(!data) - throw InvalidScalar(); + return !data.fail(); } - void Scalar::Read(long& l) + bool Scalar::Read(long& l) const { std::stringstream data(m_data); data >> l; - if(!data) - throw InvalidScalar(); + return !data.fail(); } - void Scalar::Read(float& f) + bool Scalar::Read(float& f) const { std::stringstream data(m_data); data >> f; - if(!data) - throw InvalidScalar(); + return !data.fail(); } - void Scalar::Read(double& d) + bool Scalar::Read(double& d) const { std::stringstream data(m_data); data >> d; - if(!data) - throw InvalidScalar(); + return !data.fail(); } - void Scalar::Read(char& c) + bool Scalar::Read(char& c) const { std::stringstream data(m_data); data >> c; - if(!data) - throw InvalidScalar(); + return !data.fail(); } int Scalar::Compare(Content *pContent) diff --git a/src/scalar.h b/src/scalar.h index ea6e055..3dab558 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -17,13 +17,13 @@ namespace YAML virtual bool IsScalar() const { return true; } // extraction - virtual void Read(std::string& s); - virtual void Read(int& i); - virtual void Read(unsigned& u); - virtual void Read(long& l); - virtual void Read(float& f); - virtual void Read(double& d); - virtual void Read(char& c); + virtual bool Read(std::string& s) const; + virtual bool Read(int& i) const; + virtual bool Read(unsigned& u) const; + virtual bool Read(long& l) const; + virtual bool Read(float& f) const; + virtual bool Read(double& d) const; + virtual bool Read(char& c) const; // ordering virtual int Compare(Content *pContent); From d1ef1e8ef14265d7c8ae41155cf84abfe52f147c Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 25 Sep 2008 00:15:40 +0000 Subject: [PATCH 073/295] Added more natural ways to parse boolean values (based on the YAML spec). (Thanks to Vadim Zeitlin) --- include/node.h | 1 + src/content.h | 1 + src/node.cpp | 8 ++++ src/scalar.cpp | 76 +++++++++++++++++++++++++++++++++++++ src/scalar.h | 1 + yaml-reader.vcproj | 2 + yaml-reader/main.cpp | 16 ++++---- yaml-reader/tests/test.yaml | 8 +++- 8 files changed, 103 insertions(+), 10 deletions(-) diff --git a/include/node.h b/include/node.h index f970f4f..ebfcdd9 100644 --- a/include/node.h +++ b/include/node.h @@ -40,6 +40,7 @@ namespace YAML bool Read(float& f) const; bool Read(double& d) const; bool Read(char& c) const; + bool Read(bool& b) const; // so you can specialize for other values template diff --git a/src/content.h b/src/content.h index 9561a4b..33e0d7d 100644 --- a/src/content.h +++ b/src/content.h @@ -43,6 +43,7 @@ namespace YAML virtual bool Read(float& f) const { return false; } virtual bool Read(double& d) const { return false; } virtual bool Read(char& c) const { return false; } + virtual bool Read(bool& b) const { return false; } // ordering virtual int Compare(Content *pContent) { return 0; } diff --git a/src/node.cpp b/src/node.cpp index df79ad4..48b81ec 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -293,6 +293,14 @@ namespace YAML return m_pContent->Read(c); } + bool Node::Read(bool& b) const + { + if(!m_pContent) + return false; + + return m_pContent->Read(b); + } + std::ostream& operator << (std::ostream& out, const Node& node) { node.Write(out, 0, false, false); diff --git a/src/scalar.cpp b/src/scalar.cpp index 00985cb..03dfa4b 100644 --- a/src/scalar.cpp +++ b/src/scalar.cpp @@ -5,6 +5,7 @@ #include "exceptions.h" #include "node.h" #include +#include namespace YAML { @@ -86,6 +87,81 @@ namespace YAML return !data.fail(); } + namespace + { + // we're not gonna mess with the mess that is all the isupper/etc. functions + bool IsLower(char ch) { return 'a' <= ch && ch <= 'z'; } + bool IsUpper(char ch) { return 'A' <= ch && ch <= 'Z'; } + char ToLower(char ch) { return IsUpper(ch) ? ch + 'a' - 'A' : ch; } + + std::string tolower(const std::string& str) + { + std::string s(str); + std::transform(s.begin(), s.end(), s.begin(), ToLower); + return s; + } + + template + bool IsEntirely(const std::string& str, T func) + { + for(unsigned i=0;iCompare(this); diff --git a/src/scalar.h b/src/scalar.h index 3dab558..4ccf932 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -24,6 +24,7 @@ namespace YAML virtual bool Read(float& f) const; virtual bool Read(double& d) const; virtual bool Read(char& c) const; + virtual bool Read(bool& b) const; // ordering virtual int Compare(Content *pContent); diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index 0d7cdda..f2522d1 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -58,6 +58,7 @@ /> #include -#ifdef _MSC_VER -#ifdef _DEBUG -#pragma comment(lib, "yamlcppd.lib") -#else -#pragma comment(lib, "yamlcpp.lib") -#endif // _DEBUG -#endif // _MSC_VER - void run() { std::ifstream fin("tests/test.yaml"); try { YAML::Parser parser(fin); - parser.PrintTokens(std::cout); + YAML::Node doc; + parser.GetNextDocument(doc); + for(unsigned i=0;i> value; + std::cout << (value ? "true" : "false") << "\n"; + } } catch(YAML::Exception&) { std::cout << "Error parsing the yaml!\n"; } diff --git a/yaml-reader/tests/test.yaml b/yaml-reader/tests/test.yaml index 6938c5c..34499d1 100644 --- a/yaml-reader/tests/test.yaml +++ b/yaml-reader/tests/test.yaml @@ -1 +1,7 @@ -bad YAML: [ \ No newline at end of file +- true +- n +- Off +- YES +- on +- FALSE +- FaLse From 09d2858dc0178d53d3fac7f580188d1b935b17a9 Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 18 Nov 2008 04:19:50 +0000 Subject: [PATCH 074/295] Added line/column data for nodes so they can give better invalid scalar exceptions. --- yaml-reader/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yaml-reader/main.cpp b/yaml-reader/main.cpp index 2f26a32..6038d14 100644 --- a/yaml-reader/main.cpp +++ b/yaml-reader/main.cpp @@ -16,8 +16,8 @@ void run() doc[i] >> value; std::cout << (value ? "true" : "false") << "\n"; } - } catch(YAML::Exception&) { - std::cout << "Error parsing the yaml!\n"; + } catch(YAML::Exception& e) { + std::cout << "Error at line " << e.line+1 << ", col " << e.column+1 << ": " << e.msg << "\n"; } } From 27da48bac2ffc56d1a410ec5717703a537d106dc Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 18 Nov 2008 04:20:07 +0000 Subject: [PATCH 075/295] Added line/column data for nodes so they can give better invalid scalar exceptions. --- include/exceptions.h | 62 ++++++++++++++++++++++++++++++++------------ include/node.h | 9 +++++-- src/node.cpp | 4 +++ 3 files changed, 56 insertions(+), 19 deletions(-) diff --git a/include/exceptions.h b/include/exceptions.h index 427088a..5dc0062 100644 --- a/include/exceptions.h +++ b/include/exceptions.h @@ -5,23 +5,6 @@ namespace YAML { - class Exception: public std::exception {}; - class ParserException: public Exception { - public: - ParserException(int line_, int column_, const std::string& msg_) - : line(line_), column(column_), msg(msg_) {} - virtual ~ParserException() throw () {} - - int line, column; - std::string msg; - }; - - class RepresentationException: public Exception {}; - - // representation exceptions - class InvalidScalar: public RepresentationException {}; - class BadDereference: public RepresentationException {}; - // error messages namespace ErrorMsg { @@ -55,5 +38,50 @@ namespace YAML const std::string CHAR_IN_ANCHOR = "illegal character found while scanning anchor"; const std::string ZERO_INDENT_IN_BLOCK = "cannot set zero indentation for a block scalar"; const std::string CHAR_IN_BLOCK = "unexpected character in block scalar"; + + const std::string INVALID_SCALAR = "invalid scalar"; + const std::string KEY_NOT_FOUND = "key not found"; + const std::string BAD_DEREFERENCE = "bad dereference"; } + + class Exception: public std::exception { + public: + Exception(int line_, int column_, const std::string& msg_) + : line(line_), column(column_), msg(msg_) {} + virtual ~Exception() throw () {} + + int line, column; + std::string msg; + }; + + class ParserException: public Exception { + public: + ParserException(int line_, int column_, const std::string& msg_) + : Exception(line_, column_, msg_) {} + }; + + class RepresentationException: public Exception { + public: + RepresentationException(int line_, int column_, const std::string& msg_) + : Exception(line_, column_, msg_) {} + }; + + // representation exceptions + class InvalidScalar: public RepresentationException { + public: + InvalidScalar(int line_, int column_) + : RepresentationException(line_, column_, ErrorMsg::INVALID_SCALAR) {} + }; + + class KeyNotFound: public RepresentationException { + public: + KeyNotFound(int line_, int column_) + : RepresentationException(line_, column_, ErrorMsg::KEY_NOT_FOUND) {} + }; + + class BadDereference: public RepresentationException { + public: + BadDereference() + : RepresentationException(-1, -1, ErrorMsg::BAD_DEREFERENCE) {} + }; } diff --git a/include/node.h b/include/node.h index ebfcdd9..cb627fe 100644 --- a/include/node.h +++ b/include/node.h @@ -27,6 +27,10 @@ namespace YAML CONTENT_TYPE GetType() const; + // file location of start of this node + int GetLine() const { return m_line; } + int GetColumn() const { return m_column; } + // accessors Iterator begin() const; Iterator end() const; @@ -81,6 +85,7 @@ namespace YAML void ParseAlias(Scanner *pScanner, const ParserState& state); private: + int m_line, m_column; std::string m_anchor, m_tag; Content *m_pContent; bool m_alias; @@ -97,7 +102,7 @@ namespace YAML inline void operator >> (const Node& node, T& value) { if(!Read(node, value)) - throw InvalidScalar(); + throw InvalidScalar(node.m_line, node.m_column); } template @@ -114,7 +119,7 @@ namespace YAML } } - throw BadDereference(); + throw KeyNotFound(m_line, m_column); } template diff --git a/src/node.cpp b/src/node.cpp index 48b81ec..a7a3573 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -37,6 +37,10 @@ namespace YAML { Clear(); + // save location + m_line = pScanner->peek().line; + m_column = pScanner->peek().column; + ParseHeader(pScanner, state); // is this an alias? if so, it can have no content From 4b45a7185a77318a2e36658e6f73cdc66f288272 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 20 Nov 2008 03:41:40 +0000 Subject: [PATCH 076/295] Replaced a pointer-centered try/catch block with std::auto_ptr --- src/map.cpp | 68 ++++++++++++++++++++++------------------------------- 1 file changed, 28 insertions(+), 40 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 89f5b70..4af27c3 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -5,6 +5,7 @@ #include "token.h" #include "exceptions.h" #include +#include namespace YAML { @@ -66,25 +67,19 @@ namespace YAML if(token.type == TT_BLOCK_END) break; - Node *pKey = new Node; - Node *pValue = new Node; + std::auto_ptr pKey(new Node), pValue(new Node); - try { - // grab key - pKey->Parse(pScanner, state); + // grab key + pKey->Parse(pScanner, state); - // now grab value (optional) - if(!pScanner->empty() && pScanner->peek().type == TT_VALUE) { - pScanner->pop(); - pValue->Parse(pScanner, state); - } - - m_data[pKey] = pValue; - } catch(Exception&) { - delete pKey; - delete pValue; - throw; + // now grab value (optional) + if(!pScanner->empty() && pScanner->peek().type == TT_VALUE) { + pScanner->pop(); + pValue->Parse(pScanner, state); } + + // assign the map with the actual pointers + m_data[pKey.release()] = pValue.release(); } } @@ -110,33 +105,26 @@ namespace YAML pScanner->pop(); - Node *pKey = new Node; - Node *pValue = new Node; + std::auto_ptr pKey(new Node), pValue(new Node); - try { - // grab key - pKey->Parse(pScanner, state); + // grab key + pKey->Parse(pScanner, state); - // now grab value (optional) - if(!pScanner->empty() && pScanner->peek().type == TT_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 == TT_FLOW_ENTRY) - pScanner->pop(); - else if(nextToken.type != TT_FLOW_MAP_END) - throw ParserException(nextToken.line, nextToken.column, ErrorMsg::END_OF_MAP_FLOW); - - m_data[pKey] = pValue; - } catch(Exception&) { - // clean up and rethrow - delete pKey; - delete pValue; - throw; + // now grab value (optional) + if(!pScanner->empty() && pScanner->peek().type == TT_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 == TT_FLOW_ENTRY) + pScanner->pop(); + else if(nextToken.type != TT_FLOW_MAP_END) + throw ParserException(nextToken.line, nextToken.column, ErrorMsg::END_OF_MAP_FLOW); + + // assign the map with the actual pointers + m_data[pKey.release()] = pValue.release(); } } From ad2b9fbaaf1a36d3645417b9ac657b053635b4dd Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 20 Nov 2008 04:12:31 +0000 Subject: [PATCH 077/295] Fixed tag output bug --- src/node.cpp | 6 +++++- yaml-reader/tests/directives.yaml | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/node.cpp b/src/node.cpp index a7a3573..23df5a3 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -136,7 +136,11 @@ namespace YAML // write tag if(m_tag != "") { - out << std::string("!<") << m_tag << std::string("> "); + // put the tag in the "proper" brackets + if(m_tag.substr(0, 2) == "!<" && m_tag.substr(m_tag.size() - 1) == ">") + out << m_tag; + else + out << std::string("!<") << m_tag << std::string("> "); startedLine = true; onlyOneCharOnLine = false; } diff --git a/yaml-reader/tests/directives.yaml b/yaml-reader/tests/directives.yaml index adc9130..5e81cdd 100644 --- a/yaml-reader/tests/directives.yaml +++ b/yaml-reader/tests/directives.yaml @@ -2,4 +2,4 @@ %TAG ! !howdy --- - basic node -- ! yeah baby \ No newline at end of file +- ! yeah baby From 51ea36e444078015bb814b80aeeb2b80759292e6 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 1 Jan 2009 02:40:18 +0000 Subject: [PATCH 078/295] Added a templated derived exception to KeyNotFound so that you can figure out *which* key wasn't found. --- include/exceptions.h | 14 ++++++++++++++ include/node.h | 2 +- yaml-reader/main.cpp | 12 +++++++----- yaml-reader/tests/test.yaml | 10 +++------- 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/include/exceptions.h b/include/exceptions.h index 5dc0062..9e41e00 100644 --- a/include/exceptions.h +++ b/include/exceptions.h @@ -79,6 +79,20 @@ namespace YAML : RepresentationException(line_, column_, ErrorMsg::KEY_NOT_FOUND) {} }; + template + class TypedKeyNotFound: public KeyNotFound { + public: + TypedKeyNotFound(int line_, int column_, const T& key_) + : KeyNotFound(line_, column_), key(key_) {} + + T key; + }; + + template + TypedKeyNotFound MakeTypedKeyNotFound(int line, int column, const T& key) { + return TypedKeyNotFound (line, column, key); + } + class BadDereference: public RepresentationException { public: BadDereference() diff --git a/include/node.h b/include/node.h index cb627fe..8900382 100644 --- a/include/node.h +++ b/include/node.h @@ -119,7 +119,7 @@ namespace YAML } } - throw KeyNotFound(m_line, m_column); + throw MakeTypedKeyNotFound(m_line, m_column, key); } template diff --git a/yaml-reader/main.cpp b/yaml-reader/main.cpp index 6038d14..b2c20bb 100644 --- a/yaml-reader/main.cpp +++ b/yaml-reader/main.cpp @@ -11,11 +11,13 @@ void run() YAML::Parser parser(fin); YAML::Node doc; parser.GetNextDocument(doc); - for(unsigned i=0;i> value; - std::cout << (value ? "true" : "false") << "\n"; - } + + std::cout << "name: " << doc["name"] << "\n"; + std::cout << "age: " << doc["age"] << "\n"; + } catch(YAML::TypedKeyNotFound & e) { + std::cout << "Key '" << e.key << "' not found at line " << e.line+1 << ", col " << e.column+1 << "\n"; + } catch(YAML::KeyNotFound& e) { + std::cout << "Key not found at line " << e.line+1 << ", col " << e.column+1 << "\n"; } catch(YAML::Exception& e) { std::cout << "Error at line " << e.line+1 << ", col " << e.column+1 << ": " << e.msg << "\n"; } diff --git a/yaml-reader/tests/test.yaml b/yaml-reader/tests/test.yaml index 34499d1..c266abf 100644 --- a/yaml-reader/tests/test.yaml +++ b/yaml-reader/tests/test.yaml @@ -1,7 +1,3 @@ -- true -- n -- Off -- YES -- on -- FALSE -- FaLse +name: Brett Favre +position: QB +teams: [ Falcons, Packers, Jets ] \ No newline at end of file From 4cebe50a9f23517d9d5e0d27d0a62d50eb28b195 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 1 Jan 2009 20:14:32 +0000 Subject: [PATCH 079/295] Removed throw() specifier in Exception (I don't remember putting it in). This may solve a gcc error (I haven't tested it yet) or it may break it further. --- include/exceptions.h | 2 +- include/parser.h | 4 ++-- yaml-reader.vcproj | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/exceptions.h b/include/exceptions.h index 9e41e00..41603fe 100644 --- a/include/exceptions.h +++ b/include/exceptions.h @@ -48,7 +48,7 @@ namespace YAML public: Exception(int line_, int column_, const std::string& msg_) : line(line_), column(column_), msg(msg_) {} - virtual ~Exception() throw () {} + virtual ~Exception() {} int line, column; std::string msg; diff --git a/include/parser.h b/include/parser.h index 83f611b..78ad52c 100644 --- a/include/parser.h +++ b/include/parser.h @@ -32,8 +32,8 @@ namespace YAML private: // can't copy this - Parser(const Parser& rhs) {} - Parser& operator = (const Parser& rhs) { return *this; } + Parser(const Parser&) {} + Parser& operator = (const Parser&) { return *this; } private: Scanner *m_pScanner; diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index f2522d1..57d70b9 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -115,7 +115,7 @@ AdditionalIncludeDirectories="include" RuntimeLibrary="2" EnableFunctionLevelLinking="true" - WarningLevel="3" + WarningLevel="4" DebugInformationFormat="3" /> Date: Thu, 1 Jan 2009 23:59:37 +0000 Subject: [PATCH 080/295] Re-added the throw() specification to ~Exception(), and also to ~TypedKeyNotFound(); I suppose this'll fix the gcc compiler error. --- include/exceptions.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/exceptions.h b/include/exceptions.h index 41603fe..ce00bba 100644 --- a/include/exceptions.h +++ b/include/exceptions.h @@ -48,7 +48,7 @@ namespace YAML public: Exception(int line_, int column_, const std::string& msg_) : line(line_), column(column_), msg(msg_) {} - virtual ~Exception() {} + virtual ~Exception() throw() {} int line, column; std::string msg; @@ -84,6 +84,7 @@ namespace YAML public: TypedKeyNotFound(int line_, int column_, const T& key_) : KeyNotFound(line_, column_), key(key_) {} + ~TypedKeyNotFound() throw() {} T key; }; From d44502c979ae46a1add73d112cd60b1d99028331 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 15 Jan 2009 17:12:13 +0000 Subject: [PATCH 081/295] Applied patch for gcc -Wall --- src/map.cpp | 1 + src/node.cpp | 2 ++ src/regex.cpp | 1 + src/sequence.cpp | 1 + 4 files changed, 5 insertions(+) diff --git a/src/map.cpp b/src/map.cpp index 4af27c3..b7a7ec8 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -47,6 +47,7 @@ namespace YAML switch(pScanner->peek().type) { case TT_BLOCK_MAP_START: ParseBlock(pScanner, state); break; case TT_FLOW_MAP_START: ParseFlow(pScanner, state); break; + default: break; } } diff --git a/src/node.cpp b/src/node.cpp index 23df5a3..cce1d7e 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -64,6 +64,8 @@ namespace YAML m_pContent = new Map; m_pContent->Parse(pScanner, state); break; + default: + break; } } diff --git a/src/regex.cpp b/src/regex.cpp index 9c0e217..ea6e4ee 100644 --- a/src/regex.cpp +++ b/src/regex.cpp @@ -74,6 +74,7 @@ namespace YAML case REGEX_AND: m_pOp = new AndOperator; break; case REGEX_NOT: m_pOp = new NotOperator; break; case REGEX_SEQ: m_pOp = new SeqOperator; break; + default: break; } } diff --git a/src/sequence.cpp b/src/sequence.cpp index df4a201..f2272ba 100644 --- a/src/sequence.cpp +++ b/src/sequence.cpp @@ -57,6 +57,7 @@ namespace YAML case TT_BLOCK_SEQ_START: ParseBlock(pScanner, state); break; case TT_BLOCK_ENTRY: ParseImplicit(pScanner, state); break; case TT_FLOW_SEQ_START: ParseFlow(pScanner, state); break; + default: break; } } From 4e2e644c35f60c29d0446dffddf13305bc49dd8d Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 27 Jan 2009 20:16:30 +0000 Subject: [PATCH 082/295] Included for strcmp --- yaml-reader/main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yaml-reader/main.cpp b/yaml-reader/main.cpp index b2c20bb..e5833ba 100644 --- a/yaml-reader/main.cpp +++ b/yaml-reader/main.cpp @@ -2,6 +2,7 @@ #include "tests.h" #include #include +#include void run() { @@ -27,7 +28,7 @@ int main(int argc, char **argv) { bool verbose = false; for(int i=1;i Date: Tue, 27 Jan 2009 21:08:40 +0000 Subject: [PATCH 083/295] Included for gcc-4.4 (issue 9) --- src/exp.h | 1 + src/parser.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/exp.h b/src/exp.h index 7811bd2..d3e2fb6 100644 --- a/src/exp.h +++ b/src/exp.h @@ -3,6 +3,7 @@ #include "regex.h" #include #include +#include #include "stream.h" namespace YAML diff --git a/src/parser.cpp b/src/parser.cpp index d0ba2b2..3ec4773 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -4,6 +4,7 @@ #include "token.h" #include "exceptions.h" #include +#include namespace YAML { From 855d0d60df31073e3cf38f28fdefce88696657e1 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sun, 1 Feb 2009 20:48:43 +0000 Subject: [PATCH 084/295] Switched to reading the entire file into a buffer at the start.\nThis speeds it up a TON (like 100x). --- src/exp.h | 7 +++--- src/regex.cpp | 46 +++++++++++++++---------------------- src/regex.h | 23 +++++++++---------- src/scanner.cpp | 2 +- src/simplekey.cpp | 4 ++-- src/stream.cpp | 27 ++++++++++++++++------ src/stream.h | 19 ++++++++------- yaml-reader/main.cpp | 15 ++++-------- yaml-reader/tests/test.yaml | 4 +--- 9 files changed, 72 insertions(+), 75 deletions(-) diff --git a/src/exp.h b/src/exp.h index d3e2fb6..e878a80 100644 --- a/src/exp.h +++ b/src/exp.h @@ -3,7 +3,6 @@ #include "regex.h" #include #include -#include #include "stream.h" namespace YAML @@ -24,10 +23,10 @@ namespace YAML // actual tags - const RegEx DocStart = RegEx("---") + (BlankOrBreak || RegEx(EOF) || RegEx()); - const RegEx DocEnd = RegEx("...") + (BlankOrBreak || RegEx(EOF) || RegEx()); + const RegEx DocStart = RegEx("---") + (BlankOrBreak || RegEx()); + const RegEx DocEnd = RegEx("...") + (BlankOrBreak || RegEx()); const RegEx DocIndicator = DocStart || DocEnd; - const RegEx BlockEntry = RegEx('-') + (BlankOrBreak || RegEx(EOF)); + const RegEx BlockEntry = RegEx('-') + BlankOrBreak; const RegEx Key = RegEx('?'), KeyInFlow = RegEx('?') + BlankOrBreak; const RegEx Value = RegEx(':') + BlankOrBreak, diff --git a/src/regex.cpp b/src/regex.cpp index ea6e4ee..3982301 100644 --- a/src/regex.cpp +++ b/src/regex.cpp @@ -90,12 +90,12 @@ namespace YAML return Match(str) >= 0; } - bool RegEx::Matches(std::istream& in) const + bool RegEx::Matches(const char *buffer) const { - return Match(in) >= 0; + return Match(buffer) >= 0; } - bool RegEx::Matches(Stream& in) const + bool RegEx::Matches(const Stream& in) const { return Match(in) >= 0; } @@ -115,9 +115,9 @@ namespace YAML } // Match - int RegEx::Match(Stream& in) const + int RegEx::Match(const Stream& in) const { - return Match(in.stream()); + return Match(in.current()); } // Match @@ -126,19 +126,12 @@ namespace YAML // . Note: the istream is not a const reference, but we guarantee // that the pointer will be in the same spot, and we'll clear its // flags before we end. - int RegEx::Match(std::istream& in) const + int RegEx::Match(const char *buffer) const { if(!m_pOp) return -1; - int pos = in.tellg(); - int ret = m_pOp->Match(in, *this); - - // reset input stream! - in.clear(); - in.seekg(pos); - - return ret; + return m_pOp->Match(buffer, *this); } RegEx operator ! (const RegEx& ex) @@ -184,9 +177,9 @@ namespace YAML } - int RegEx::MatchOperator::Match(std::istream& in, const RegEx& regex) const + int RegEx::MatchOperator::Match(const char *buffer, const RegEx& regex) const { - if(!in || in.peek() != regex.m_a) + if(buffer[0] != regex.m_a) return -1; return 1; } @@ -199,9 +192,9 @@ namespace YAML return 1; } - int RegEx::RangeOperator::Match(std::istream& in, const RegEx& regex) const + int RegEx::RangeOperator::Match(const char *buffer, const RegEx& regex) const { - if(!in || regex.m_a > in.peek() || regex.m_z < in.peek()) + if(regex.m_a > buffer[0] || regex.m_z < buffer[0]) return -1; return 1; } @@ -217,10 +210,10 @@ namespace YAML return -1; } - int RegEx::OrOperator::Match(std::istream& in, const RegEx& regex) const + int RegEx::OrOperator::Match(const char *buffer, const RegEx& regex) const { for(unsigned i=0;i= 0) return n; } @@ -244,11 +237,11 @@ namespace YAML return first; } - int RegEx::AndOperator::Match(std::istream& in, const RegEx& regex) const + int RegEx::AndOperator::Match(const char *buffer, const RegEx& regex) const { int first = -1; for(unsigned i=0;i= 0) + if(regex.m_params[0].Match(buffer) >= 0) return -1; return 1; } @@ -289,16 +282,15 @@ namespace YAML return offset; } - int RegEx::SeqOperator::Match(std::istream& in, const RegEx& regex) const + int RegEx::SeqOperator::Match(const char *buffer, const RegEx& regex) const { int offset = 0; for(unsigned i=0;i #include -#include namespace YAML { @@ -19,37 +18,37 @@ namespace YAML struct Operator { virtual ~Operator() {} virtual int Match(const std::string& str, const RegEx& regex) const = 0; - virtual int Match(std::istream& in, const RegEx& regex) const = 0; + virtual int Match(const char *buffer, const RegEx& regex) const = 0; }; struct MatchOperator: public Operator { virtual int Match(const std::string& str, const RegEx& regex) const; - virtual int Match(std::istream& in, const RegEx& regex) const; + virtual int Match(const char *buffer, const RegEx& regex) const; }; struct RangeOperator: public Operator { virtual int Match(const std::string& str, const RegEx& regex) const; - virtual int Match(std::istream& in, const RegEx& regex) const; + virtual int Match(const char *buffer, const RegEx& regex) const; }; struct OrOperator: public Operator { virtual int Match(const std::string& str, const RegEx& regex) const; - virtual int Match(std::istream& in, const RegEx& regex) const; + virtual int Match(const char *buffer, const RegEx& regex) const; }; struct AndOperator: public Operator { virtual int Match(const std::string& str, const RegEx& regex) const; - virtual int Match(std::istream& in, const RegEx& regex) const; + virtual int Match(const char *buffer, const RegEx& regex) const; }; struct NotOperator: public Operator { virtual int Match(const std::string& str, const RegEx& regex) const; - virtual int Match(std::istream& in, const RegEx& regex) const; + virtual int Match(const char *buffer, const RegEx& regex) const; }; struct SeqOperator: public Operator { virtual int Match(const std::string& str, const RegEx& regex) const; - virtual int Match(std::istream& in, const RegEx& regex) const; + virtual int Match(const char *buffer, const RegEx& regex) const; }; public: @@ -66,11 +65,11 @@ namespace YAML bool Matches(char ch) const; bool Matches(const std::string& str) const; - bool Matches(std::istream& in) const; - bool Matches(Stream& in) const; + bool Matches(const char *buffer) const; + bool Matches(const Stream& in) const; int Match(const std::string& str) const; - int Match(std::istream& in) const; - int Match(Stream& in) const; + int Match(const char *buffer) const; + int Match(const Stream& in) const; friend RegEx operator ! (const RegEx& ex); friend RegEx operator || (const RegEx& ex1, const RegEx& ex2); diff --git a/src/scanner.cpp b/src/scanner.cpp index 5aed8d5..1d148d9 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -100,7 +100,7 @@ namespace YAML // ***** // end of stream - if(INPUT.peek() == EOF) + if(!INPUT) return EndStream(); if(INPUT.column == 0 && INPUT.peek() == Keys::Directive) diff --git a/src/simplekey.cpp b/src/simplekey.cpp index f971c54..667d683 100644 --- a/src/simplekey.cpp +++ b/src/simplekey.cpp @@ -32,7 +32,7 @@ namespace YAML // and saves it on a stack. void Scanner::InsertSimpleKey() { - SimpleKey key(INPUT.pos(), INPUT.line, INPUT.column, m_flowLevel); + SimpleKey key(INPUT.pos, INPUT.line, INPUT.column, m_flowLevel); // first add a map start, if necessary key.pMapStart = PushIndentTo(INPUT.column, false); @@ -78,7 +78,7 @@ namespace YAML isValid = false; // also needs to be less than 1024 characters and inline - if(INPUT.line != key.line || INPUT.pos() - key.pos > 1024) + if(INPUT.line != key.line || INPUT.pos - key.pos > 1024) isValid = false; // invalidate key diff --git a/src/stream.cpp b/src/stream.cpp index b388899..dc5a3ad 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -4,26 +4,39 @@ namespace YAML { - int Stream::pos() const + Stream::Stream(std::istream& input): buffer(0), pos(0), line(0), column(0), size(0) { - return input.tellg(); + std::streambuf *pBuf = input.rdbuf(); + + // store entire file in buffer + size = pBuf->pubseekoff(0, std::ios::end, std::ios::in); + pBuf->pubseekpos(0, std::ios::in); + buffer = new char[size]; + pBuf->sgetn(buffer, size); } - + + Stream::~Stream() + { + delete [] buffer; + } + + char Stream::peek() { - return input.peek(); + return buffer[pos]; } - Stream::operator bool() + Stream::operator bool() const { - return input.good(); + return pos < size; } // get // . Extracts a character from the stream and updates our position char Stream::get() { - char ch = input.get(); + char ch = buffer[pos]; + pos++; column++; if(ch == '\n') { column = 0; diff --git a/src/stream.h b/src/stream.h index 0276134..5f12f79 100644 --- a/src/stream.h +++ b/src/stream.h @@ -5,21 +5,24 @@ namespace YAML { - struct Stream + class Stream { - Stream(std::istream& input_): input(input_), line(0), column(0) {} + public: + Stream(std::istream& input); + ~Stream(); - int pos() const; - operator bool(); - bool operator !() { return !(*this); } + operator bool() const; + bool operator !() const { return !static_cast (*this); } - std::istream& stream() const { return input; } + const char *current() const { return buffer + pos; } char peek(); char get(); std::string get(int n); void eat(int n = 1); - std::istream& input; - int line, column; + int pos, line, column, size; + + private: + char *buffer; }; } diff --git a/yaml-reader/main.cpp b/yaml-reader/main.cpp index e5833ba..00e47ed 100644 --- a/yaml-reader/main.cpp +++ b/yaml-reader/main.cpp @@ -7,20 +7,13 @@ void run() { std::ifstream fin("tests/test.yaml"); + YAML::Parser parser(fin); - try { - YAML::Parser parser(fin); + while(parser) + { YAML::Node doc; parser.GetNextDocument(doc); - - std::cout << "name: " << doc["name"] << "\n"; - std::cout << "age: " << doc["age"] << "\n"; - } catch(YAML::TypedKeyNotFound & e) { - std::cout << "Key '" << e.key << "' not found at line " << e.line+1 << ", col " << e.column+1 << "\n"; - } catch(YAML::KeyNotFound& e) { - std::cout << "Key not found at line " << e.line+1 << ", col " << e.column+1 << "\n"; - } catch(YAML::Exception& e) { - std::cout << "Error at line " << e.line+1 << ", col " << e.column+1 << ": " << e.msg << "\n"; + std::cout << doc; } } diff --git a/yaml-reader/tests/test.yaml b/yaml-reader/tests/test.yaml index c266abf..32d3ff8 100644 --- a/yaml-reader/tests/test.yaml +++ b/yaml-reader/tests/test.yaml @@ -1,3 +1 @@ -name: Brett Favre -position: QB -teams: [ Falcons, Packers, Jets ] \ No newline at end of file +- test From 7297387015d061cbbe093b9a24f9c6c0493b4b13 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sat, 7 Feb 2009 07:57:13 +0000 Subject: [PATCH 085/295] Fixed several bugs from the new file i/o setup. In particular: 1. Windows CR/LF weren't read properly (issue #11) 2. Scanning wasn't reading EOF properly 3. Documents may be empty (this was old, I think) Also fixed some VS2008 warnings on /W4. --- src/content.h | 34 +++++++++++++++++----------------- src/map.h | 4 ++-- src/node.cpp | 4 ++++ src/regex.cpp | 31 ++++++++++++++----------------- src/regex.h | 22 ++++++++++++---------- src/scalar.h | 4 ++-- src/scanscalar.cpp | 4 ++-- src/scantoken.cpp | 12 ++++++------ src/sequence.h | 4 ++-- src/stream.cpp | 7 ++++++- src/stream.h | 15 ++++++++++++++- yaml-reader/tests/test.yaml | 3 ++- yamlcpp.vcproj | 4 ++-- 13 files changed, 85 insertions(+), 63 deletions(-) diff --git a/src/content.h b/src/content.h index 33e0d7d..f689cd6 100644 --- a/src/content.h +++ b/src/content.h @@ -25,31 +25,31 @@ namespace YAML virtual void Parse(Scanner *pScanner, const ParserState& state) = 0; virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) = 0; - virtual bool GetBegin(std::vector ::const_iterator& it) const { return false; } - virtual bool GetBegin(std::map ::const_iterator& it) const { return false; } - virtual bool GetEnd(std::vector ::const_iterator& it) const { return false; } - virtual bool GetEnd(std::map ::const_iterator& it) const { return false; } - virtual Node *GetNode(unsigned i) const { return 0; } + virtual bool GetBegin(std::vector ::const_iterator&) const { return false; } + virtual bool GetBegin(std::map ::const_iterator&) const { return false; } + virtual bool GetEnd(std::vector ::const_iterator&) const { return false; } + virtual bool GetEnd(std::map ::const_iterator&) const { return false; } + virtual Node *GetNode(unsigned) const { return 0; } virtual unsigned GetSize() const { return 0; } virtual bool IsScalar() const { return false; } virtual bool IsMap() const { return false; } virtual bool IsSequence() const { return false; } // extraction - virtual bool Read(std::string& s) const { return false; } - virtual bool Read(int& i) const { return false; } - virtual bool Read(unsigned& u) const { return false; } - virtual bool Read(long& l) const { return false; } - virtual bool Read(float& f) const { return false; } - virtual bool Read(double& d) const { return false; } - virtual bool Read(char& c) const { return false; } - virtual bool Read(bool& b) const { return false; } + virtual bool Read(std::string&) const { return false; } + virtual bool Read(int&) const { return false; } + virtual bool Read(unsigned&) const { return false; } + virtual bool Read(long&) const { return false; } + virtual bool Read(float&) const { return false; } + virtual bool Read(double&) const { return false; } + virtual bool Read(char&) const { return false; } + virtual bool Read(bool&) const { return false; } // ordering - virtual int Compare(Content *pContent) { return 0; } - virtual int Compare(Scalar *pScalar) { return 0; } - virtual int Compare(Sequence *pSeq) { return 0; } - virtual int Compare(Map *pMap) { return 0; } + virtual int Compare(Content *) { return 0; } + virtual int Compare(Scalar *) { return 0; } + virtual int Compare(Sequence *) { return 0; } + virtual int Compare(Map *) { return 0; } protected: }; diff --git a/src/map.h b/src/map.h index 0f7c3bf..be722f4 100644 --- a/src/map.h +++ b/src/map.h @@ -23,8 +23,8 @@ namespace YAML // ordering virtual int Compare(Content *pContent); - virtual int Compare(Scalar *pScalar) { return 1; } - virtual int Compare(Sequence *pSeq) { return 1; } + virtual int Compare(Scalar *) { return 1; } + virtual int Compare(Sequence *) { return 1; } virtual int Compare(Map *pMap); private: diff --git a/src/node.cpp b/src/node.cpp index cce1d7e..8c86882 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -37,6 +37,10 @@ namespace YAML { Clear(); + // an empty node *is* a possibility + if(pScanner->empty()) + return; + // save location m_line = pScanner->peek().line; m_column = pScanner->peek().column; diff --git a/src/regex.cpp b/src/regex.cpp index 3982301..4ffd711 100644 --- a/src/regex.cpp +++ b/src/regex.cpp @@ -90,7 +90,7 @@ namespace YAML return Match(str) >= 0; } - bool RegEx::Matches(const char *buffer) const + bool RegEx::Matches(const Buffer& buffer) const { return Match(buffer) >= 0; } @@ -109,7 +109,7 @@ namespace YAML int RegEx::Match(const std::string& str) const { if(!m_pOp) - return 0; + return str.empty() ? 0 : -1; // the empty regex only is successful on the empty string return m_pOp->Match(str, *this); } @@ -121,15 +121,12 @@ namespace YAML } // Match - // . The stream version does the same thing as the string version; - // REMEMBER that we only match from the start of the stream! - // . Note: the istream is not a const reference, but we guarantee - // that the pointer will be in the same spot, and we'll clear its - // flags before we end. - int RegEx::Match(const char *buffer) const + // . The buffer version does the same thing as the string version; + // REMEMBER that we only match from the start of the buffer! + int RegEx::Match(const Buffer& buffer) const { if(!m_pOp) - return -1; + return !buffer ? 0 : -1; // see above return m_pOp->Match(buffer, *this); } @@ -177,9 +174,9 @@ namespace YAML } - int RegEx::MatchOperator::Match(const char *buffer, const RegEx& regex) const + int RegEx::MatchOperator::Match(const Buffer& buffer, const RegEx& regex) const { - if(buffer[0] != regex.m_a) + if(!buffer || buffer[0] != regex.m_a) return -1; return 1; } @@ -192,9 +189,9 @@ namespace YAML return 1; } - int RegEx::RangeOperator::Match(const char *buffer, const RegEx& regex) const + int RegEx::RangeOperator::Match(const Buffer& buffer, const RegEx& regex) const { - if(regex.m_a > buffer[0] || regex.m_z < buffer[0]) + if(!buffer || regex.m_a > buffer[0] || regex.m_z < buffer[0]) return -1; return 1; } @@ -210,7 +207,7 @@ namespace YAML return -1; } - int RegEx::OrOperator::Match(const char *buffer, const RegEx& regex) const + int RegEx::OrOperator::Match(const Buffer& buffer, const RegEx& regex) const { for(unsigned i=0;ipubseekoff(0, std::ios::end, std::ios::in); pBuf->pubseekpos(0, std::ios::in); buffer = new char[size]; - pBuf->sgetn(buffer, size); + size = pBuf->sgetn(buffer, size); // Note: when reading a Windows CR/LF file, + // pubseekoff() counts CR/LF as two characters, + // setgn() reads CR/LF as a single LF character! } Stream::~Stream() diff --git a/src/stream.h b/src/stream.h index 5f12f79..d35f3fe 100644 --- a/src/stream.h +++ b/src/stream.h @@ -5,6 +5,19 @@ namespace YAML { + // a simple buffer wrapper that knows how big it is + struct Buffer { + Buffer(char *b, int s): buffer(b), size(s) {} + + operator bool() const { return size > 0; } + bool operator !() const { return !static_cast (*this); } + char operator [] (int i) const { return buffer[i]; } + const Buffer operator + (int offset) const { return Buffer(buffer + offset, size - offset); } + + char *buffer; + int size; + }; + class Stream { public: @@ -14,7 +27,7 @@ namespace YAML operator bool() const; bool operator !() const { return !static_cast (*this); } - const char *current() const { return buffer + pos; } + const Buffer current() const { return Buffer(buffer + pos, size - pos); } char peek(); char get(); std::string get(int n); diff --git a/yaml-reader/tests/test.yaml b/yaml-reader/tests/test.yaml index 32d3ff8..00e30f5 100644 --- a/yaml-reader/tests/test.yaml +++ b/yaml-reader/tests/test.yaml @@ -1 +1,2 @@ -- test +--- +... \ No newline at end of file diff --git a/yamlcpp.vcproj b/yamlcpp.vcproj index ee5923c..58a1736 100644 --- a/yamlcpp.vcproj +++ b/yamlcpp.vcproj @@ -47,7 +47,7 @@ BasicRuntimeChecks="3" RuntimeLibrary="3" UsePrecompiledHeader="0" - WarningLevel="3" + WarningLevel="4" DebugInformationFormat="3" /> Date: Fri, 22 May 2009 21:48:05 +0000 Subject: [PATCH 086/295] Merged aliases branch into trunk, changes r100:150 --- include/exceptions.h | 2 + include/node.h | 7 ++ src/CMakeLists.txt | 2 +- src/alias.cpp | 125 +++++++++++++++++++++++++++++++++ src/alias.h | 42 +++++++++++ src/node.cpp | 70 +++++++++++++----- src/parser.cpp | 3 + src/scanner.cpp | 51 +++++++++++++- src/scanner.h | 10 +++ src/stream.cpp | 1 + yaml-reader/tests.cpp | 1 + yaml-reader/tests/aliased.yaml | 4 ++ yamlcpp.vcproj | 8 +++ 13 files changed, 308 insertions(+), 18 deletions(-) create mode 100644 src/alias.cpp create mode 100644 src/alias.h create mode 100644 yaml-reader/tests/aliased.yaml diff --git a/include/exceptions.h b/include/exceptions.h index ce00bba..8378369 100644 --- a/include/exceptions.h +++ b/include/exceptions.h @@ -38,6 +38,8 @@ namespace YAML const std::string CHAR_IN_ANCHOR = "illegal character found while scanning anchor"; const std::string ZERO_INDENT_IN_BLOCK = "cannot set zero indentation for a block scalar"; const std::string CHAR_IN_BLOCK = "unexpected character in block scalar"; + const std::string AMBIGUOUS_ANCHOR = "cannot assign the same alias to multiple nodes"; + const std::string UNKNOWN_ANCHOR = "the referenced anchor is not defined"; const std::string INVALID_SCALAR = "invalid scalar"; const std::string KEY_NOT_FOUND = "key not found"; diff --git a/include/node.h b/include/node.h index 8900382..0dcac18 100644 --- a/include/node.h +++ b/include/node.h @@ -66,6 +66,11 @@ namespace YAML const Node& operator [] (unsigned u) const; const Node& operator [] (int i) const; + // for anchors/aliases + const Node *Identity() const { return m_pIdentity; } + bool IsAlias() const { return m_alias; } + bool IsReferenced() const { return m_referenced; } + // insertion friend std::ostream& operator << (std::ostream& out, const Node& node); @@ -89,6 +94,8 @@ namespace YAML std::string m_anchor, m_tag; Content *m_pContent; bool m_alias; + const Node *m_pIdentity; + mutable bool m_referenced; }; // templated things we need to keep inline in the header diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d2cd7bf..9753189 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,4 +1,4 @@ -set(FILES content.cpp iterator.cpp node.cpp parserstate.cpp +set(FILES alias.cpp content.cpp iterator.cpp node.cpp parserstate.cpp scalar.cpp scanscalar.cpp sequence.cpp stream.cpp exp.cpp map.cpp parser.cpp regex.cpp scanner.cpp scantoken.cpp simplekey.cpp) diff --git a/src/alias.cpp b/src/alias.cpp new file mode 100644 index 0000000..e8a4560 --- /dev/null +++ b/src/alias.cpp @@ -0,0 +1,125 @@ +#include "crt.h" +#include "alias.h" +#include + +namespace YAML +{ + Alias::Alias(Content* pNodeContent) + : m_pRef(pNodeContent) + { + } + + void Alias::Parse(Scanner *pScanner, const ParserState& state) + { + } + + void Alias::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) + { + out << "\n"; + } + + bool Alias::GetBegin(std::vector ::const_iterator& i) const + { + return m_pRef->GetBegin(i); + } + + bool Alias::GetBegin(std::map ::const_iterator& i) const + { + return m_pRef->GetBegin(i); + } + + bool Alias::GetEnd(std::vector ::const_iterator& i) const + { + return m_pRef->GetEnd(i); + } + + bool Alias::GetEnd(std::map ::const_iterator& i) const + { + return m_pRef->GetEnd(i); + } + + Node* Alias::GetNode(unsigned n) const + { + return m_pRef->GetNode(n); + } + + unsigned Alias::GetSize() const + { + return m_pRef->GetSize(); + } + + bool Alias::IsScalar() const + { + return m_pRef->IsScalar(); + } + + bool Alias::IsMap() const + { + return m_pRef->IsMap(); + } + + bool Alias::IsSequence() const + { + return m_pRef->IsSequence(); + } + + bool Alias::Read(std::string& v) const + { + return m_pRef->Read(v); + } + + bool Alias::Read(int& v) const + { + return m_pRef->Read(v); + } + + bool Alias::Read(unsigned& v) const + { + return m_pRef->Read(v); + } + + bool Alias::Read(long& v) const + { + return m_pRef->Read(v); + } + + bool Alias::Read(float& v) const + { + return m_pRef->Read(v); + } + + bool Alias::Read(double& v) const + { + return m_pRef->Read(v); + } + + bool Alias::Read(char& v) const + { + return m_pRef->Read(v); + } + + bool Alias::Read(bool& v) const + { + return m_pRef->Read(v); + } + + int Alias::Compare(Content *pContent) + { + return m_pRef->Compare(pContent); + } + + int Alias::Compare(Scalar *pScalar) + { + return m_pRef->Compare(pScalar); + } + + int Alias::Compare(Sequence *pSequence) + { + return m_pRef->Compare(pSequence); + } + + int Alias::Compare(Map *pMap) + { + return m_pRef->Compare(pMap); + } +} diff --git a/src/alias.h b/src/alias.h new file mode 100644 index 0000000..2f15d67 --- /dev/null +++ b/src/alias.h @@ -0,0 +1,42 @@ +#pragma once + +#include "content.h" + +namespace YAML +{ + class Alias : public Content + { + public: + Alias(Content *pNodeContent); + + virtual void Parse(Scanner* pScanner, const ParserState& state); + virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); + + virtual bool GetBegin(std::vector ::const_iterator&) const; + virtual bool GetBegin(std::map ::const_iterator&) const; + virtual bool GetEnd(std::vector ::const_iterator&) const; + virtual bool GetEnd(std::map ::const_iterator&) const; + virtual Node* GetNode(unsigned) const; + virtual unsigned GetSize() const; + virtual bool IsScalar() const; + virtual bool IsMap() const; + virtual bool IsSequence() const; + + virtual bool Read(std::string&) const; + virtual bool Read(int&) const; + virtual bool Read(unsigned&) const; + virtual bool Read(long&) const; + virtual bool Read(float&) const; + virtual bool Read(double&) const; + virtual bool Read(char&) const; + virtual bool Read(bool&) const; + + virtual int Compare(Content *); + virtual int Compare(Scalar *); + virtual int Compare(Sequence *); + virtual int Compare(Map *); + + private: + Content* m_pRef; + }; +} diff --git a/src/node.cpp b/src/node.cpp index 8c86882..bb365eb 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -7,7 +7,9 @@ #include "scalar.h" #include "sequence.h" #include "map.h" +#include "alias.h" #include "iterpriv.h" +#include namespace YAML { @@ -17,7 +19,7 @@ namespace YAML return *pNode1 < *pNode2; } - Node::Node(): m_pContent(0), m_alias(false) + Node::Node(): m_pContent(0), m_alias(false), m_pIdentity(this), m_referenced(true) { } @@ -31,6 +33,9 @@ namespace YAML delete m_pContent; m_pContent = 0; m_alias = false; + m_referenced = false; + m_anchor.clear(); + m_tag.clear(); } void Node::Parse(Scanner *pScanner, const ParserState& state) @@ -47,30 +52,50 @@ namespace YAML ParseHeader(pScanner, state); - // is this an alias? if so, it can have no content - if(m_alias) + // 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 Alias(pAliasedContent); + return; + } // now split based on what kind of node we should be switch(pScanner->peek().type) { case TT_SCALAR: m_pContent = new Scalar; - m_pContent->Parse(pScanner, state); break; case TT_FLOW_SEQ_START: case TT_BLOCK_SEQ_START: case TT_BLOCK_ENTRY: m_pContent = new Sequence; - m_pContent->Parse(pScanner, state); break; case TT_FLOW_MAP_START: case TT_BLOCK_MAP_START: m_pContent = new Map; - m_pContent->Parse(pScanner, state); break; default: 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 @@ -129,33 +154,46 @@ namespace YAML void Node::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const { + // If using an anchor or tag for the whole document, document start + // must be explicit + bool indicateDocStart = (indent == 0); + // write anchor/alias if(m_anchor != "") { + if (indicateDocStart) { + out << "--- "; + indicateDocStart = false; + } + if(m_alias) - out << std::string("*"); + out << "*"; else - out << std::string("&"); - out << m_anchor << std::string(" "); + out << "&"; + out << m_anchor << " "; startedLine = true; onlyOneCharOnLine = false; } // write tag if(m_tag != "") { + if (indicateDocStart) { + out << "--- "; + indicateDocStart = false; + } + // put the tag in the "proper" brackets - if(m_tag.substr(0, 2) == "!<" && m_tag.substr(m_tag.size() - 1) == ">") - out << m_tag; + if(m_tag.substr(0, 2) == std::string("!<") && m_tag.substr(m_tag.size() - 1) == std::string(">")) + out << m_tag << " "; else - out << std::string("!<") << m_tag << std::string("> "); + out << "!<" << m_tag << "> "; startedLine = true; onlyOneCharOnLine = false; } - if(!m_pContent) { - out << std::string("\n"); - } else { + if(!m_pContent) + out << "\n"; + else m_pContent->Write(out, indent, startedLine, onlyOneCharOnLine); - } } CONTENT_TYPE Node::GetType() const diff --git a/src/parser.cpp b/src/parser.cpp index 3ec4773..6b49429 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -55,6 +55,9 @@ namespace YAML // and finally eat any doc ends we see while(!m_pScanner->empty() && m_pScanner->peek().type == TT_DOC_END) m_pScanner->pop(); + + // clear anchors from the scanner, which are no longer relevant + m_pScanner->ClearAnchors(); } // ParseDirectives diff --git a/src/scanner.cpp b/src/scanner.cpp index 1d148d9..c89b105 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -29,8 +29,13 @@ namespace YAML void Scanner::pop() { EnsureTokensInQueue(); - if(!m_tokens.empty()) + if(!m_tokens.empty()) { + // Saved anchors shouldn't survive popping the document end marker + if (m_tokens.front().type == TT_DOC_END) { + ClearAnchors(); + } m_tokens.pop(); + } } // peek @@ -217,6 +222,7 @@ namespace YAML m_startedStream = true; m_simpleKeyAllowed = true; m_indents.push(-1); + m_anchors.clear(); } // EndStream @@ -273,4 +279,47 @@ namespace YAML m_tokens.push(Token(TT_BLOCK_END, INPUT.line, INPUT.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 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). + // . Does not parse any more tokens. + void Scanner::ThrowParserException(const std::string& msg) const + { + int line = -1, column = -1; + if(!m_tokens.empty()) { + const Token& token = m_tokens.front(); + line = token.line; + column = token.column; + } + throw ParserException(line, column, msg); + } + + void Scanner::ClearAnchors() + { + m_anchors.clear(); + } } diff --git a/src/scanner.h b/src/scanner.h index e4590ef..f2f7df2 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -5,11 +5,14 @@ #include #include #include +#include #include "stream.h" #include "token.h" namespace YAML { + class Node; + class Scanner { public: @@ -21,6 +24,11 @@ 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: // scanning void EnsureTokensInQueue(); @@ -35,6 +43,7 @@ namespace YAML void InsertSimpleKey(); bool VerifySimpleKey(bool force = false); void VerifyAllSimpleKeys(); + void ThrowParserException(const std::string& msg) const; bool IsWhitespaceToBeEaten(char ch); @@ -81,5 +90,6 @@ namespace YAML bool m_isLastKeyValid; std::stack m_simpleKeys; std::stack m_indents; + std::map m_anchors; }; } diff --git a/src/stream.cpp b/src/stream.cpp index aa957c3..97da1d4 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -55,6 +55,7 @@ namespace YAML std::string Stream::get(int n) { std::string ret; + ret.reserve(n); for(int i=0;i + + @@ -257,6 +261,10 @@ + + From cba20711b027799082b032c17a05ca5012360fb5 Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 22 May 2009 21:52:31 +0000 Subject: [PATCH 087/295] Merged emitter branch into trunk, changes r105:r151 --- include/emitter.h | 85 +++++ include/emittermanip.h | 84 +++++ include/exceptions.h | 83 +++-- include/noncopyable.h | 16 + include/ostream.h | 31 ++ include/stlemitter.h | 38 +++ src/CMakeLists.txt | 4 +- src/emitter.cpp | 697 +++++++++++++++++++++++++++++++++++++++++ src/emitterstate.cpp | 263 ++++++++++++++++ src/emitterstate.h | 195 ++++++++++++ src/emitterutils.cpp | 143 +++++++++ src/emitterutils.h | 18 ++ src/exp.h | 5 +- src/indentation.h | 30 ++ src/ostream.cpp | 63 ++++ src/setting.h | 97 ++++++ src/stream.h | 5 +- yaml-reader/main.cpp | 6 + yaml-reader/tests.cpp | 603 +++++++++++++++++++++++++++++++++++ yaml-reader/tests.h | 49 +++ 20 files changed, 2478 insertions(+), 37 deletions(-) create mode 100644 include/emitter.h create mode 100644 include/emittermanip.h create mode 100644 include/noncopyable.h create mode 100644 include/ostream.h create mode 100644 include/stlemitter.h create mode 100644 src/emitter.cpp create mode 100644 src/emitterstate.cpp create mode 100644 src/emitterstate.h create mode 100644 src/emitterutils.cpp create mode 100644 src/emitterutils.h create mode 100644 src/indentation.h create mode 100644 src/ostream.cpp create mode 100644 src/setting.h diff --git a/include/emitter.h b/include/emitter.h new file mode 100644 index 0000000..92d9993 --- /dev/null +++ b/include/emitter.h @@ -0,0 +1,85 @@ +#pragma once + +#include "emittermanip.h" +#include "ostream.h" +#include +#include + +namespace YAML +{ + class EmitterState; + + class Emitter + { + public: + Emitter(); + ~Emitter(); + + bool WriteToStream(std::ostream& out) const; + bool WriteToFile(const std::string& fileName) const; + + // state checking + bool good() const; + const std::string GetLastError() const; + + // global setters + bool SetStringFormat(EMITTER_MANIP value); + bool SetBoolFormat(EMITTER_MANIP value); + bool SetIntBase(EMITTER_MANIP value); + bool SetSeqFormat(EMITTER_MANIP value); + bool SetMapFormat(EMITTER_MANIP value); + bool SetIndent(unsigned n); + bool SetPreCommentIndent(unsigned n); + bool SetPostCommentIndent(unsigned n); + + // local setters + Emitter& SetLocalValue(EMITTER_MANIP value); + Emitter& SetLocalIndent(const _Indent& indent); + + // overloads of write + Emitter& Write(const std::string& str); + Emitter& Write(const char *str); + Emitter& Write(int i); + Emitter& Write(bool b); + Emitter& Write(float f); + Emitter& Write(double d); + Emitter& Write(const _Alias& alias); + Emitter& Write(const _Anchor& anchor); + Emitter& Write(const _Comment& comment); + + private: + enum ATOMIC_TYPE { AT_SCALAR, AT_SEQ, AT_BLOCK_SEQ, AT_FLOW_SEQ, AT_MAP, AT_BLOCK_MAP, AT_FLOW_MAP }; + + void PreAtomicWrite(); + bool GotoNextPreAtomicState(); + void PostAtomicWrite(); + void EmitSeparationIfNecessary(); + + void EmitBeginSeq(); + void EmitEndSeq(); + void EmitBeginMap(); + void EmitEndMap(); + void EmitKey(); + void EmitValue(); + + private: + ostream m_stream; + std::auto_ptr m_pState; + }; + + // overloads of insertion + template + inline Emitter& operator << (Emitter& emitter, T v) { + return emitter.Write(v); + } + + template <> + inline Emitter& operator << (Emitter& emitter, EMITTER_MANIP value) { + return emitter.SetLocalValue(value); + } + + template <> + inline Emitter& operator << (Emitter& emitter, _Indent indent) { + return emitter.SetLocalIndent(indent); + } +} diff --git a/include/emittermanip.h b/include/emittermanip.h new file mode 100644 index 0000000..05a9e64 --- /dev/null +++ b/include/emittermanip.h @@ -0,0 +1,84 @@ +#pragma once + +#include + +namespace YAML +{ + enum EMITTER_MANIP { + // general manipulators + Auto, + + // string manipulators + // Auto, // duplicate + SingleQuoted, + DoubleQuoted, + Literal, + + // bool manipulators + YesNoBool, // yes, no + TrueFalseBool, // true, false + OnOffBool, // on, off + UpperCase, // TRUE, N + LowerCase, // f, yes + CamelCase, // No, Off + LongBool, // yes, On + ShortBool, // y, t + + // int manipulators + Dec, + Hex, + Oct, + + // sequence manipulators + BeginSeq, + EndSeq, + Flow, + Block, + + // map manipulators + BeginMap, + EndMap, + Key, + Value, + // Flow, // duplicate + // Block, // duplicate + // Auto, // duplicate + LongKey, + }; + + struct _Indent { + _Indent(int value_): value(value_) {} + int value; + }; + + inline _Indent Indent(int value) { + return _Indent(value); + } + + struct _Alias { + _Alias(const std::string& content_): content(content_) {} + std::string content; + }; + + inline _Alias Alias(const std::string content) { + return _Alias(content); + } + + struct _Anchor { + _Anchor(const std::string& content_): content(content_) {} + std::string content; + }; + + inline _Anchor Anchor(const std::string content) { + return _Anchor(content); + } + + struct _Comment { + _Comment(const std::string& content_): content(content_) {} + std::string content; + }; + + inline _Comment Comment(const std::string content) { + return _Comment(content); + } +} diff --git a/include/exceptions.h b/include/exceptions.h index 8378369..784dc05 100644 --- a/include/exceptions.h +++ b/include/exceptions.h @@ -8,42 +8,53 @@ namespace YAML // error messages namespace ErrorMsg { - const std::string YAML_DIRECTIVE_ARGS = "YAML directives must have exactly one argument"; - const std::string YAML_VERSION = "bad YAML version: "; - const std::string YAML_MAJOR_VERSION = "YAML major version too large"; - const std::string TAG_DIRECTIVE_ARGS = "TAG directives must have exactly two arguments"; - const std::string END_OF_MAP = "end of map not found"; - const std::string END_OF_MAP_FLOW = "end of map flow not found"; - const std::string END_OF_SEQ = "end of sequence not found"; - const std::string END_OF_SEQ_FLOW = "end of sequence flow not found"; - const std::string MULTIPLE_TAGS = "cannot assign multiple tags to the same node"; - const std::string MULTIPLE_ANCHORS = "cannot assign multiple anchors to the same node"; - const std::string MULTIPLE_ALIASES = "cannot assign multiple aliases to the same node"; - const std::string ALIAS_CONTENT = "aliases can't have any content, *including* tags"; - const std::string INVALID_HEX = "bad character found while scanning hex number"; - const std::string INVALID_UNICODE = "invalid unicode: "; - const std::string INVALID_ESCAPE = "unknown escape character: "; - const std::string UNKNOWN_TOKEN = "unknown token"; - const std::string DOC_IN_SCALAR = "illegal document indicator in scalar"; - const std::string EOF_IN_SCALAR = "illegal EOF in scalar"; - const std::string CHAR_IN_SCALAR = "illegal character in scalar"; - const std::string TAB_IN_INDENTATION = "illegal tab when looking for indentation"; - const std::string FLOW_END = "illegal flow end"; - const std::string BLOCK_ENTRY = "illegal block entry"; - const std::string MAP_KEY = "illegal map key"; - const std::string MAP_VALUE = "illegal map value"; - const std::string ALIAS_NOT_FOUND = "alias not found after *"; - const std::string ANCHOR_NOT_FOUND = "anchor not found after &"; - const std::string CHAR_IN_ALIAS = "illegal character found while scanning alias"; - const std::string CHAR_IN_ANCHOR = "illegal character found while scanning anchor"; - const std::string ZERO_INDENT_IN_BLOCK = "cannot set zero indentation for a block scalar"; - const std::string CHAR_IN_BLOCK = "unexpected character in block scalar"; + const std::string YAML_DIRECTIVE_ARGS = "YAML directives must have exactly one argument"; + const std::string YAML_VERSION = "bad YAML version: "; + const std::string YAML_MAJOR_VERSION = "YAML major version too large"; + const std::string TAG_DIRECTIVE_ARGS = "TAG directives must have exactly two arguments"; + const std::string END_OF_MAP = "end of map not found"; + const std::string END_OF_MAP_FLOW = "end of map flow not found"; + const std::string END_OF_SEQ = "end of sequence not found"; + const std::string END_OF_SEQ_FLOW = "end of sequence flow not found"; + const std::string MULTIPLE_TAGS = "cannot assign multiple tags to the same node"; + const std::string MULTIPLE_ANCHORS = "cannot assign multiple anchors to the same node"; + const std::string MULTIPLE_ALIASES = "cannot assign multiple aliases to the same node"; + const std::string ALIAS_CONTENT = "aliases can't have any content, *including* tags"; + const std::string INVALID_HEX = "bad character found while scanning hex number"; + const std::string INVALID_UNICODE = "invalid unicode: "; + const std::string INVALID_ESCAPE = "unknown escape character: "; + const std::string UNKNOWN_TOKEN = "unknown token"; + const std::string DOC_IN_SCALAR = "illegal document indicator in scalar"; + const std::string EOF_IN_SCALAR = "illegal EOF in scalar"; + const std::string CHAR_IN_SCALAR = "illegal character in scalar"; + const std::string TAB_IN_INDENTATION = "illegal tab when looking for indentation"; + const std::string FLOW_END = "illegal flow end"; + const std::string BLOCK_ENTRY = "illegal block entry"; + const std::string MAP_KEY = "illegal map key"; + const std::string MAP_VALUE = "illegal map value"; + const std::string ALIAS_NOT_FOUND = "alias not found after *"; + const std::string ANCHOR_NOT_FOUND = "anchor not found after &"; + const std::string CHAR_IN_ALIAS = "illegal character found while scanning alias"; + const std::string CHAR_IN_ANCHOR = "illegal character found while scanning anchor"; + const std::string ZERO_INDENT_IN_BLOCK = "cannot set zero indentation for a block scalar"; + const std::string CHAR_IN_BLOCK = "unexpected character in block scalar"; const std::string AMBIGUOUS_ANCHOR = "cannot assign the same alias to multiple nodes"; const std::string UNKNOWN_ANCHOR = "the referenced anchor is not defined"; - const std::string INVALID_SCALAR = "invalid scalar"; - const std::string KEY_NOT_FOUND = "key not found"; - const std::string BAD_DEREFERENCE = "bad dereference"; + const std::string INVALID_SCALAR = "invalid scalar"; + const std::string KEY_NOT_FOUND = "key not found"; + const std::string BAD_DEREFERENCE = "bad dereference"; + + const std::string UNMATCHED_GROUP_TAG = "unmatched group tag"; + const std::string UNEXPECTED_END_SEQ = "unexpected end sequence token"; + const std::string UNEXPECTED_END_MAP = "unexpected end map token"; + const std::string SINGLE_QUOTED_CHAR = "invalid character in single-quoted string"; + const std::string INVALID_ANCHOR = "invalid anchor"; + const std::string INVALID_ALIAS = "invalid alias"; + const std::string EXPECTED_KEY_TOKEN = "expected key token"; + const std::string EXPECTED_VALUE_TOKEN = "expected value token"; + const std::string UNEXPECTED_KEY_TOKEN = "unexpected key token"; + const std::string UNEXPECTED_VALUE_TOKEN = "unexpected value token"; } class Exception: public std::exception { @@ -101,4 +112,10 @@ namespace YAML BadDereference() : RepresentationException(-1, -1, ErrorMsg::BAD_DEREFERENCE) {} }; + + class EmitterException: public Exception { + public: + EmitterException(const std::string& msg_) + : Exception(-1, -1, msg_) {} + }; } diff --git a/include/noncopyable.h b/include/noncopyable.h new file mode 100644 index 0000000..2ae4c68 --- /dev/null +++ b/include/noncopyable.h @@ -0,0 +1,16 @@ +#pragma once + +namespace YAML +{ + // this is basically boost::noncopyable + class noncopyable + { + protected: + noncopyable() {} + ~noncopyable() {} + + private: + noncopyable(const noncopyable&); + const noncopyable& operator = (const noncopyable&); + }; +} diff --git a/include/ostream.h b/include/ostream.h new file mode 100644 index 0000000..5051576 --- /dev/null +++ b/include/ostream.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +namespace YAML +{ + class ostream + { + public: + ostream(); + ~ostream(); + + void reserve(unsigned size); + void put(char ch); + const char *str() const { return m_buffer; } + + unsigned row() const { return m_row; } + unsigned col() const { return m_col; } + + private: + char *m_buffer; + unsigned m_pos; + unsigned m_size; + + unsigned m_row, m_col; + }; + + ostream& operator << (ostream& out, const char *str); + ostream& operator << (ostream& out, const std::string& str); + ostream& operator << (ostream& out, char ch); +} diff --git a/include/stlemitter.h b/include/stlemitter.h new file mode 100644 index 0000000..5caa872 --- /dev/null +++ b/include/stlemitter.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include + +namespace YAML +{ + template + inline Emitter& operator << (Emitter& emitter, const std::vector & v) { + typedef typename std::vector vec; + emitter << BeginSeq; + for(typename vec::const_iterator it=v.begin();it!=v.end();++it) + emitter << *it; + emitter << EndSeq; + return emitter; + } + + template + inline Emitter& operator << (Emitter& emitter, const std::list & v) { + typedef typename std::list list; + emitter << BeginSeq; + for(typename list::const_iterator it=v.begin();it!=v.end();++it) + emitter << *it; + emitter << EndSeq; + return emitter; + } + + template + inline Emitter& operator << (Emitter& emitter, const std::map & m) { + typedef typename std::map map; + emitter << BeginMap; + for(typename map::const_iterator it=m.begin();it!=m.end();++it) + emitter << Key << it->first << Value << it->second; + emitter << EndMap; + return emitter; + } +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9753189..8e59ffe 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,9 @@ set(FILES alias.cpp content.cpp iterator.cpp node.cpp parserstate.cpp scalar.cpp scanscalar.cpp sequence.cpp stream.cpp exp.cpp map.cpp parser.cpp regex.cpp scanner.cpp - scantoken.cpp simplekey.cpp) + scantoken.cpp simplekey.cpp + emitter.cpp emitterstate.h emitterstate.cpp emitterutils.h emitterutils.cpp + ostream.cpp) include_directories(${YAML_CPP_SOURCE_DIR}/include) add_library(yaml-cpp ${FILES}) diff --git a/src/emitter.cpp b/src/emitter.cpp new file mode 100644 index 0000000..bdc2fba --- /dev/null +++ b/src/emitter.cpp @@ -0,0 +1,697 @@ +#include "emitter.h" +#include "emitterstate.h" +#include "emitterutils.h" +#include "indentation.h" +#include "exceptions.h" +#include +#include + +namespace YAML +{ + Emitter::Emitter(): m_pState(new EmitterState) + { + } + + Emitter::~Emitter() + { + } + + bool Emitter::WriteToStream(std::ostream& out) const + { + out << m_stream.str(); + return true; + } + + bool Emitter::WriteToFile(const std::string& fileName) const + { + std::ofstream fout(fileName.c_str()); + if(!fout) + return false; + + return WriteToStream(fout); + } + + // state checking + bool Emitter::good() const + { + return m_pState->good(); + } + + const std::string Emitter::GetLastError() const + { + return m_pState->GetLastError(); + } + + // global setters + bool Emitter::SetStringFormat(EMITTER_MANIP value) + { + return m_pState->SetStringFormat(value, GLOBAL); + } + + bool Emitter::SetBoolFormat(EMITTER_MANIP value) + { + bool ok = false; + if(m_pState->SetBoolFormat(value, GLOBAL)) + ok = true; + if(m_pState->SetBoolCaseFormat(value, GLOBAL)) + ok = true; + if(m_pState->SetBoolLengthFormat(value, GLOBAL)) + ok = true; + return ok; + } + + bool Emitter::SetIntBase(EMITTER_MANIP value) + { + return m_pState->SetIntFormat(value, GLOBAL); + } + + bool Emitter::SetSeqFormat(EMITTER_MANIP value) + { + return m_pState->SetFlowType(GT_SEQ, value, GLOBAL); + } + + bool Emitter::SetMapFormat(EMITTER_MANIP value) + { + bool ok = false; + if(m_pState->SetFlowType(GT_MAP, value, GLOBAL)) + ok = true; + if(m_pState->SetMapKeyFormat(value, GLOBAL)) + ok = true; + return ok; + } + + bool Emitter::SetIndent(unsigned n) + { + return m_pState->SetIndent(n, GLOBAL); + } + + bool Emitter::SetPreCommentIndent(unsigned n) + { + return m_pState->SetPreCommentIndent(n, GLOBAL); + } + + bool Emitter::SetPostCommentIndent(unsigned n) + { + return m_pState->SetPostCommentIndent(n, GLOBAL); + } + + // SetLocalValue + // . Either start/end a group, or set a modifier locally + Emitter& Emitter::SetLocalValue(EMITTER_MANIP value) + { + if(!good()) + return *this; + + switch(value) { + case BeginSeq: + EmitBeginSeq(); + break; + case EndSeq: + EmitEndSeq(); + break; + case BeginMap: + EmitBeginMap(); + break; + case EndMap: + EmitEndMap(); + break; + case Key: + EmitKey(); + break; + case Value: + EmitValue(); + break; + default: + m_pState->SetLocalValue(value); + break; + } + return *this; + } + + Emitter& Emitter::SetLocalIndent(const _Indent& indent) + { + m_pState->SetIndent(indent.value, LOCAL); + return *this; + } + + // GotoNextPreAtomicState + // . Runs the state machine, emitting if necessary, and returns 'true' if done (i.e., ready to emit an atom) + bool Emitter::GotoNextPreAtomicState() + { + if(!good()) + return true; + + unsigned curIndent = m_pState->GetCurIndent(); + + EMITTER_STATE curState = m_pState->GetCurState(); + switch(curState) { + // document-level + case ES_WAITING_FOR_DOC: + std::cerr << "waiting for doc (pre)\n"; + m_pState->SwitchState(ES_WRITING_DOC); + return true; + case ES_WRITING_DOC: + std::cerr << "writing doc (pre)\n"; + return true; + + // block sequence + case ES_WAITING_FOR_BLOCK_SEQ_ENTRY: + std::cerr << "waiting for block seq entry (pre)\n"; + m_stream << IndentTo(curIndent) << "-"; + m_pState->RequireSeparation(); + m_pState->SwitchState(ES_WRITING_BLOCK_SEQ_ENTRY); + return true; + case ES_WRITING_BLOCK_SEQ_ENTRY: + std::cerr << "writing block seq entry (pre)\n"; + return true; + case ES_DONE_WITH_BLOCK_SEQ_ENTRY: + std::cerr << "done with block seq entry (pre)\n"; + m_stream << '\n'; + m_pState->SwitchState(ES_WAITING_FOR_BLOCK_SEQ_ENTRY); + return false; + + // flow sequence + case ES_WAITING_FOR_FLOW_SEQ_ENTRY: + std::cerr << "waiting for flow seq entry (pre)\n"; + m_pState->SwitchState(ES_WRITING_FLOW_SEQ_ENTRY); + return true; + case ES_WRITING_FLOW_SEQ_ENTRY: + std::cerr << "writing flow seq entry (pre)\n"; + return true; + case ES_DONE_WITH_FLOW_SEQ_ENTRY: + std::cerr << "done with flow seq entry (pre)\n"; + m_stream << ','; + m_pState->RequireSeparation(); + m_pState->SwitchState(ES_WAITING_FOR_FLOW_SEQ_ENTRY); + return false; + + // block map + case ES_WAITING_FOR_BLOCK_MAP_ENTRY: + std::cerr << "waiting for block map entry (pre)\n"; + m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN); + return true; + case ES_WAITING_FOR_BLOCK_MAP_KEY: + std::cerr << "waiting for block map key (pre)\n"; + if(m_pState->CurrentlyInLongKey()) { + m_stream << IndentTo(curIndent) << '?'; + m_pState->RequireSeparation(); + } + m_pState->SwitchState(ES_WRITING_BLOCK_MAP_KEY); + return true; + case ES_WRITING_BLOCK_MAP_KEY: + std::cerr << "writing block map key (pre)\n"; + return true; + case ES_DONE_WITH_BLOCK_MAP_KEY: + std::cerr << "done with block map key (pre)\n"; + m_pState->SetError(ErrorMsg::EXPECTED_VALUE_TOKEN); + return true; + case ES_WAITING_FOR_BLOCK_MAP_VALUE: + std::cerr << "waiting for block map value (pre)\n"; + if(m_pState->CurrentlyInLongKey()) + m_stream << IndentTo(curIndent); + m_stream << ':'; + m_pState->RequireSeparation(); + m_pState->SwitchState(ES_WRITING_BLOCK_MAP_VALUE); + return true; + case ES_WRITING_BLOCK_MAP_VALUE: + std::cerr << "writing block map value (pre)\n"; + return true; + case ES_DONE_WITH_BLOCK_MAP_VALUE: + std::cerr << "done with block map value (pre)\n"; + m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN); + return true; + + // flow map + case ES_WAITING_FOR_FLOW_MAP_ENTRY: + std::cerr << "waiting for flow map entry (pre)\n"; + m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN); + return true; + case ES_WAITING_FOR_FLOW_MAP_KEY: + std::cerr << "waiting for flow map key (pre)\n"; + m_pState->SwitchState(ES_WRITING_FLOW_MAP_KEY); + if(m_pState->CurrentlyInLongKey()) { + EmitSeparationIfNecessary(); + m_stream << '?'; + m_pState->RequireSeparation(); + } + return true; + case ES_WRITING_FLOW_MAP_KEY: + std::cerr << "writing flow map key (pre)\n"; + return true; + case ES_DONE_WITH_FLOW_MAP_KEY: + std::cerr << "done with flow map key (pre)\n"; + m_pState->SetError(ErrorMsg::EXPECTED_VALUE_TOKEN); + return true; + case ES_WAITING_FOR_FLOW_MAP_VALUE: + std::cerr << "waiting for flow map value (pre)\n"; + m_stream << ':'; + m_pState->RequireSeparation(); + m_pState->SwitchState(ES_WRITING_FLOW_MAP_VALUE); + return true; + case ES_WRITING_FLOW_MAP_VALUE: + std::cerr << "writing flow map value (pre)\n"; + return true; + case ES_DONE_WITH_FLOW_MAP_VALUE: + std::cerr << "done with flow map value (pre)\n"; + m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN); + return true; + default: + assert(false); + } + + assert(false); + return true; + } + + // PreAtomicWrite + // . Depending on the emitter state, write to the stream to get it + // in position to do an atomic write (e.g., scalar, sequence, or map) + void Emitter::PreAtomicWrite() + { + if(!good()) + return; + + while(!GotoNextPreAtomicState()) + ; + } + + // PostAtomicWrite + // . Clean up + void Emitter::PostAtomicWrite() + { + if(!good()) + return; + + EMITTER_STATE curState = m_pState->GetCurState(); + switch(curState) { + // document-level + case ES_WRITING_DOC: + m_pState->SwitchState(ES_DONE_WITH_DOC); + break; + + // block seq + case ES_WRITING_BLOCK_SEQ_ENTRY: + m_pState->SwitchState(ES_DONE_WITH_BLOCK_SEQ_ENTRY); + break; + + // flow seq + case ES_WRITING_FLOW_SEQ_ENTRY: + m_pState->SwitchState(ES_DONE_WITH_FLOW_SEQ_ENTRY); + break; + + // block map + case ES_WRITING_BLOCK_MAP_KEY: + m_pState->SwitchState(ES_DONE_WITH_BLOCK_MAP_KEY); + break; + case ES_WRITING_BLOCK_MAP_VALUE: + m_pState->SwitchState(ES_DONE_WITH_BLOCK_MAP_VALUE); + break; + + // flow map + case ES_WRITING_FLOW_MAP_KEY: + m_pState->SwitchState(ES_DONE_WITH_FLOW_MAP_KEY); + break; + case ES_WRITING_FLOW_MAP_VALUE: + m_pState->SwitchState(ES_DONE_WITH_FLOW_MAP_VALUE); + break; + default: + assert(false); + }; + + m_pState->ClearModifiedSettings(); + } + + // EmitSeparationIfNecessary + void Emitter::EmitSeparationIfNecessary() + { + if(!good()) + return; + + if(m_pState->RequiresSeparation()) + m_stream << ' '; + m_pState->UnsetSeparation(); + } + + // EmitBeginSeq + void Emitter::EmitBeginSeq() + { + if(!good()) + return; + + // must have a long key if we're emitting a sequence + m_pState->StartLongKey(); + + PreAtomicWrite(); + + EMITTER_STATE curState = m_pState->GetCurState(); + EMITTER_MANIP flowType = m_pState->GetFlowType(GT_SEQ); + if(flowType == Block) { + if(curState == ES_WRITING_BLOCK_SEQ_ENTRY || curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE) { + m_stream << "\n"; + m_pState->UnsetSeparation(); + } + m_pState->PushState(ES_WAITING_FOR_BLOCK_SEQ_ENTRY); + } else if(flowType == Flow) { + EmitSeparationIfNecessary(); + m_stream << "["; + m_pState->PushState(ES_WAITING_FOR_FLOW_SEQ_ENTRY); + } else + assert(false); + + m_pState->BeginGroup(GT_SEQ); + } + + // EmitEndSeq + void Emitter::EmitEndSeq() + { + if(!good()) + return; + + if(m_pState->GetCurGroupType() != GT_SEQ) + return m_pState->SetError(ErrorMsg::UNEXPECTED_END_SEQ); + + EMITTER_STATE curState = m_pState->GetCurState(); + FLOW_TYPE flowType = m_pState->GetCurGroupFlowType(); + if(flowType == FT_BLOCK) + assert(curState == ES_DONE_WITH_BLOCK_SEQ_ENTRY); + else if(flowType == FT_FLOW) { + m_stream << "]"; + // Note: flow sequences are allowed to be empty + assert(curState == ES_DONE_WITH_FLOW_SEQ_ENTRY || curState == ES_WAITING_FOR_FLOW_SEQ_ENTRY); + } else + assert(false); + + m_pState->PopState(); + m_pState->EndGroup(GT_SEQ); + + PostAtomicWrite(); + } + + // EmitBeginMap + void Emitter::EmitBeginMap() + { + if(!good()) + return; + + // must have a long key if we're emitting a map + m_pState->StartLongKey(); + + PreAtomicWrite(); + + EMITTER_STATE curState = m_pState->GetCurState(); + EMITTER_MANIP flowType = m_pState->GetFlowType(GT_MAP); + if(flowType == Block) { + if(curState == ES_WRITING_BLOCK_SEQ_ENTRY || curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE) { + m_stream << "\n"; + m_pState->UnsetSeparation(); + } + m_pState->PushState(ES_WAITING_FOR_BLOCK_MAP_ENTRY); + } else if(flowType == Flow) { + EmitSeparationIfNecessary(); + m_stream << "{"; + m_pState->PushState(ES_WAITING_FOR_FLOW_MAP_ENTRY); + } else + assert(false); + + m_pState->BeginGroup(GT_MAP); + } + + // EmitEndMap + void Emitter::EmitEndMap() + { + if(!good()) + return; + + if(m_pState->GetCurGroupType() != GT_MAP) + return m_pState->SetError(ErrorMsg::UNEXPECTED_END_MAP); + + EMITTER_STATE curState = m_pState->GetCurState(); + FLOW_TYPE flowType = m_pState->GetCurGroupFlowType(); + if(flowType == FT_BLOCK) + assert(curState == ES_DONE_WITH_BLOCK_MAP_VALUE); + else if(flowType == FT_FLOW) { + m_stream << "}"; + // Note: flow maps are allowed to be empty + assert(curState == ES_DONE_WITH_FLOW_MAP_VALUE || curState == ES_WAITING_FOR_FLOW_MAP_ENTRY); + } else + assert(false); + + m_pState->PopState(); + m_pState->EndGroup(GT_MAP); + + PostAtomicWrite(); + } + + // EmitKey + void Emitter::EmitKey() + { + if(!good()) + return; + + EMITTER_STATE curState = m_pState->GetCurState(); + FLOW_TYPE flowType = m_pState->GetCurGroupFlowType(); + if(curState != ES_WAITING_FOR_BLOCK_MAP_ENTRY && curState != ES_DONE_WITH_BLOCK_MAP_VALUE + && curState != ES_WAITING_FOR_FLOW_MAP_ENTRY && curState != ES_DONE_WITH_FLOW_MAP_VALUE) + return m_pState->SetError(ErrorMsg::UNEXPECTED_KEY_TOKEN); + + if(flowType == FT_BLOCK) { + if(curState == ES_DONE_WITH_BLOCK_MAP_VALUE) + m_stream << '\n'; + unsigned curIndent = m_pState->GetCurIndent(); + m_stream << IndentTo(curIndent); + m_pState->SwitchState(ES_WAITING_FOR_BLOCK_MAP_KEY); + } else if(flowType == FT_FLOW) { + if(curState == ES_DONE_WITH_FLOW_MAP_VALUE) { + m_stream << ','; + m_pState->RequireSeparation(); + } + m_pState->SwitchState(ES_WAITING_FOR_FLOW_MAP_KEY); + } else + assert(false); + + if(m_pState->GetMapKeyFormat() == LongKey) + m_pState->StartLongKey(); + else if(m_pState->GetMapKeyFormat() == Auto) + m_pState->StartSimpleKey(); + else + assert(false); + } + + // EmitValue + void Emitter::EmitValue() + { + if(!good()) + return; + + EMITTER_STATE curState = m_pState->GetCurState(); + FLOW_TYPE flowType = m_pState->GetCurGroupFlowType(); + if(curState != ES_DONE_WITH_BLOCK_MAP_KEY && curState != ES_DONE_WITH_FLOW_MAP_KEY) + return m_pState->SetError(ErrorMsg::UNEXPECTED_VALUE_TOKEN); + + if(flowType == FT_BLOCK) { + if(m_pState->CurrentlyInLongKey()) + m_stream << '\n'; + m_pState->SwitchState(ES_WAITING_FOR_BLOCK_MAP_VALUE); + } else if(flowType == FT_FLOW) { + m_pState->SwitchState(ES_WAITING_FOR_FLOW_MAP_VALUE); + } else + assert(false); + } + + // ******************************************************************************************* + // overloads of Write + + Emitter& Emitter::Write(const std::string& str) + { + if(!good()) + return *this; + + // literal scalars must use long keys + if(m_pState->GetStringFormat() == Literal && m_pState->GetCurGroupFlowType() != FT_FLOW) + m_pState->StartLongKey(); + + PreAtomicWrite(); + EmitSeparationIfNecessary(); + + EMITTER_MANIP strFmt = m_pState->GetStringFormat(); + FLOW_TYPE flowType = m_pState->GetCurGroupFlowType(); + unsigned curIndent = m_pState->GetCurIndent(); + + switch(strFmt) { + case Auto: + Utils::WriteString(m_stream, str, flowType == FT_FLOW); + break; + case SingleQuoted: + if(!Utils::WriteSingleQuotedString(m_stream, str)) { + m_pState->SetError(ErrorMsg::SINGLE_QUOTED_CHAR); + return *this; + } + break; + case DoubleQuoted: + Utils::WriteDoubleQuotedString(m_stream, str); + break; + case Literal: + if(flowType == FT_FLOW) + Utils::WriteString(m_stream, str, flowType == FT_FLOW); + else + Utils::WriteLiteralString(m_stream, str, curIndent + m_pState->GetIndent()); + break; + default: + assert(false); + } + + PostAtomicWrite(); + return *this; + } + + Emitter& Emitter::Write(const char *str) + { + if(!good()) + return *this; + + return Write(std::string(str)); + } + + Emitter& Emitter::Write(int i) + { + if(!good()) + return *this; + + PreAtomicWrite(); + EmitSeparationIfNecessary(); + + EMITTER_MANIP intFmt = m_pState->GetIntFormat(); + std::stringstream str; + switch(intFmt) { + case Dec: + str << std::dec; + break; + case Hex: + str << std::hex; + break; + case Oct: + str << std::oct; + break; + default: + assert(false); + } + + str << i; + m_stream << str.str(); + + PostAtomicWrite(); + return *this; + } + + Emitter& Emitter::Write(bool b) + { + if(!good()) + return *this; + + PreAtomicWrite(); + EmitSeparationIfNecessary(); + + // set up all possible bools to write + struct BoolName { std::string trueName, falseName; }; + struct BoolFormatNames { BoolName upper, lower, camel; }; + struct BoolTypes { BoolFormatNames yesNo, trueFalse, onOff; }; + + static const BoolTypes boolTypes = { + { { "YES", "NO" }, { "yes", "no" }, { "Yes", "No" } }, + { { "TRUE", "FALSE" }, { "true", "false" }, { "True", "False" } }, + { { "ON", "OFF" }, { "on", "off" }, { "On", "Off" } } + }; + + // select the right one + EMITTER_MANIP boolFmt = m_pState->GetBoolFormat(); + EMITTER_MANIP boolLengthFmt = m_pState->GetBoolLengthFormat(); + EMITTER_MANIP boolCaseFmt = m_pState->GetBoolCaseFormat(); + + const BoolFormatNames& fmtNames = (boolFmt == YesNoBool ? boolTypes.yesNo : boolFmt == TrueFalseBool ? boolTypes.trueFalse : boolTypes.onOff); + const BoolName& boolName = (boolCaseFmt == UpperCase ? fmtNames.upper : boolCaseFmt == LowerCase ? fmtNames.lower : fmtNames.camel); + const std::string& name = (b ? boolName.trueName : boolName.falseName); + + // and say it! + // TODO: should we disallow writing OnOffBool with ShortBool? (it'll just print "o" for both, which is silly) + if(boolLengthFmt == ShortBool) + m_stream << name[0]; + else + m_stream << name; + + PostAtomicWrite(); + return *this; + } + + Emitter& Emitter::Write(float f) + { + if(!good()) + return *this; + + PreAtomicWrite(); + EmitSeparationIfNecessary(); + + std::stringstream str; + str << f; + m_stream << str.str(); + + PostAtomicWrite(); + return *this; + } + + Emitter& Emitter::Write(double d) + { + if(!good()) + return *this; + + PreAtomicWrite(); + EmitSeparationIfNecessary(); + + std::stringstream str; + str << d; + m_stream << str.str(); + + PostAtomicWrite(); + return *this; + } + + Emitter& Emitter::Write(const _Alias& alias) + { + if(!good()) + return *this; + + PreAtomicWrite(); + EmitSeparationIfNecessary(); + if(!Utils::WriteAlias(m_stream, alias.content)) { + m_pState->SetError(ErrorMsg::INVALID_ALIAS); + return *this; + } + PostAtomicWrite(); + return *this; + } + + Emitter& Emitter::Write(const _Anchor& anchor) + { + if(!good()) + return *this; + + PreAtomicWrite(); + EmitSeparationIfNecessary(); + if(!Utils::WriteAnchor(m_stream, anchor.content)) { + m_pState->SetError(ErrorMsg::INVALID_ANCHOR); + return *this; + } + m_pState->RequireSeparation(); + // Note: no PostAtomicWrite() because we need another value for this node + return *this; + } + + Emitter& Emitter::Write(const _Comment& comment) + { + if(!good()) + return *this; + + m_stream << Indentation(m_pState->GetPreCommentIndent()); + Utils::WriteComment(m_stream, comment.content, m_pState->GetPostCommentIndent()); + return *this; + } +} diff --git a/src/emitterstate.cpp b/src/emitterstate.cpp new file mode 100644 index 0000000..5a2d8bf --- /dev/null +++ b/src/emitterstate.cpp @@ -0,0 +1,263 @@ +#include "emitterstate.h" +#include "exceptions.h" + +namespace YAML +{ + EmitterState::EmitterState(): m_isGood(true), m_curIndent(0), m_requiresSeparation(false) + { + // start up + m_stateStack.push(ES_WAITING_FOR_DOC); + + // set default global manipulators + m_strFmt.set(Auto); + m_boolFmt.set(TrueFalseBool); + m_boolLengthFmt.set(LongBool); + m_boolCaseFmt.set(LowerCase); + m_intFmt.set(Dec); + m_indent.set(2); + m_preCommentIndent.set(2); + m_postCommentIndent.set(1); + m_seqFmt.set(Block); + m_mapFmt.set(Block); + m_mapKeyFmt.set(Auto); + } + + EmitterState::~EmitterState() + { + while(!m_groups.empty()) + _PopGroup(); + } + + std::auto_ptr EmitterState::_PopGroup() + { + if(m_groups.empty()) + return std::auto_ptr (0); + + std::auto_ptr pGroup(m_groups.top()); + m_groups.pop(); + return pGroup; + } + + // SetLocalValue + // . We blindly tries to set all possible formatters to this value + // . Only the ones that make sense will be accepted + void EmitterState::SetLocalValue(EMITTER_MANIP value) + { + SetStringFormat(value, LOCAL); + SetBoolFormat(value, LOCAL); + SetBoolCaseFormat(value, LOCAL); + SetBoolLengthFormat(value, LOCAL); + SetIntFormat(value, LOCAL); + SetFlowType(GT_SEQ, value, LOCAL); + SetFlowType(GT_MAP, value, LOCAL); + SetMapKeyFormat(value, LOCAL); + } + + void EmitterState::BeginGroup(GROUP_TYPE type) + { + unsigned lastIndent = (m_groups.empty() ? 0 : m_groups.top()->indent); + m_curIndent += lastIndent; + + std::auto_ptr pGroup(new Group(type)); + + // transfer settings (which last until this group is done) + pGroup->modifiedSettings = m_modifiedSettings; + + // set up group + pGroup->flow = GetFlowType(type); + pGroup->indent = GetIndent(); + pGroup->usingLongKey = (GetMapKeyFormat() == LongKey ? true : false); + + m_groups.push(pGroup.release()); + } + + void EmitterState::EndGroup(GROUP_TYPE type) + { + if(m_groups.empty()) + return SetError(ErrorMsg::UNMATCHED_GROUP_TAG); + + // get rid of the current group + { + std::auto_ptr pFinishedGroup = _PopGroup(); + if(pFinishedGroup->type != type) + return SetError(ErrorMsg::UNMATCHED_GROUP_TAG); + } + + // reset old settings + unsigned lastIndent = (m_groups.empty() ? 0 : m_groups.top()->indent); + assert(m_curIndent >= lastIndent); + m_curIndent -= lastIndent; + + // some global settings that we changed may have been overridden + // by a local setting we just popped, so we need to restore them + m_globalModifiedSettings.restore(); + } + + GROUP_TYPE EmitterState::GetCurGroupType() const + { + if(m_groups.empty()) + return GT_NONE; + + return m_groups.top()->type; + } + + FLOW_TYPE EmitterState::GetCurGroupFlowType() const + { + if(m_groups.empty()) + return FT_NONE; + + return (m_groups.top()->flow == Flow ? FT_FLOW : FT_BLOCK); + } + + bool EmitterState::CurrentlyInLongKey() + { + if(m_groups.empty()) + return false; + return m_groups.top()->usingLongKey; + } + + void EmitterState::StartLongKey() + { + if(!m_groups.empty()) + m_groups.top()->usingLongKey = true; + } + + void EmitterState::StartSimpleKey() + { + if(!m_groups.empty()) + m_groups.top()->usingLongKey = false; + } + + void EmitterState::ClearModifiedSettings() + { + m_modifiedSettings.clear(); + } + + bool EmitterState::SetStringFormat(EMITTER_MANIP value, FMT_SCOPE scope) + { + switch(value) { + case Auto: + case SingleQuoted: + case DoubleQuoted: + case Literal: + _Set(m_strFmt, value, scope); + return true; + default: + return false; + } + } + + bool EmitterState::SetBoolFormat(EMITTER_MANIP value, FMT_SCOPE scope) + { + switch(value) { + case OnOffBool: + case TrueFalseBool: + case YesNoBool: + _Set(m_boolFmt, value, scope); + return true; + default: + return false; + } + } + + bool EmitterState::SetBoolLengthFormat(EMITTER_MANIP value, FMT_SCOPE scope) + { + switch(value) { + case LongBool: + case ShortBool: + _Set(m_boolLengthFmt, value, scope); + return true; + default: + return false; + } + } + + bool EmitterState::SetBoolCaseFormat(EMITTER_MANIP value, FMT_SCOPE scope) + { + switch(value) { + case UpperCase: + case LowerCase: + case CamelCase: + _Set(m_boolCaseFmt, value, scope); + return true; + default: + return false; + } + } + + bool EmitterState::SetIntFormat(EMITTER_MANIP value, FMT_SCOPE scope) + { + switch(value) { + case Dec: + case Hex: + case Oct: + _Set(m_intFmt, value, scope); + return true; + default: + return false; + } + } + + bool EmitterState::SetIndent(unsigned value, FMT_SCOPE scope) + { + if(value == 0) + return false; + + _Set(m_indent, value, scope); + return true; + } + + bool EmitterState::SetPreCommentIndent(unsigned value, FMT_SCOPE scope) + { + if(value == 0) + return false; + + _Set(m_preCommentIndent, value, scope); + return true; + } + + bool EmitterState::SetPostCommentIndent(unsigned value, FMT_SCOPE scope) + { + if(value == 0) + return false; + + _Set(m_postCommentIndent, value, scope); + return true; + } + + bool EmitterState::SetFlowType(GROUP_TYPE groupType, EMITTER_MANIP value, FMT_SCOPE scope) + { + switch(value) { + case Block: + case Flow: + _Set(groupType == GT_SEQ ? m_seqFmt : m_mapFmt, value, scope); + return true; + default: + return false; + } + } + + EMITTER_MANIP EmitterState::GetFlowType(GROUP_TYPE groupType) const + { + // force flow style if we're currently in a flow + FLOW_TYPE flowType = GetCurGroupFlowType(); + if(flowType == FT_FLOW) + return Flow; + + // otherwise, go with what's asked of use + return (groupType == GT_SEQ ? m_seqFmt.get() : m_mapFmt.get()); + } + + bool EmitterState::SetMapKeyFormat(EMITTER_MANIP value, FMT_SCOPE scope) + { + switch(value) { + case Auto: + case LongKey: + _Set(m_mapKeyFmt, value, scope); + return true; + default: + return false; + } + } +} + diff --git a/src/emitterstate.h b/src/emitterstate.h new file mode 100644 index 0000000..763047e --- /dev/null +++ b/src/emitterstate.h @@ -0,0 +1,195 @@ +#pragma once + +#include "setting.h" +#include "emittermanip.h" +#include +#include +#include +#include + +namespace YAML +{ + enum FMT_SCOPE { + LOCAL, + GLOBAL + }; + + enum GROUP_TYPE { + GT_NONE, + GT_SEQ, + GT_MAP + }; + + enum FLOW_TYPE { + FT_NONE, + FT_FLOW, + FT_BLOCK + }; + + enum NODE_STATE { + NS_START, + NS_READY_FOR_ATOM, + NS_END + }; + + enum EMITTER_STATE { + ES_WAITING_FOR_DOC, + ES_WRITING_DOC, + ES_DONE_WITH_DOC, + + // block seq + ES_WAITING_FOR_BLOCK_SEQ_ENTRY, + ES_WRITING_BLOCK_SEQ_ENTRY, + ES_DONE_WITH_BLOCK_SEQ_ENTRY, + + // flow seq + ES_WAITING_FOR_FLOW_SEQ_ENTRY, + ES_WRITING_FLOW_SEQ_ENTRY, + ES_DONE_WITH_FLOW_SEQ_ENTRY, + + // block map + ES_WAITING_FOR_BLOCK_MAP_ENTRY, + ES_WAITING_FOR_BLOCK_MAP_KEY, + ES_WRITING_BLOCK_MAP_KEY, + ES_DONE_WITH_BLOCK_MAP_KEY, + ES_WAITING_FOR_BLOCK_MAP_VALUE, + ES_WRITING_BLOCK_MAP_VALUE, + ES_DONE_WITH_BLOCK_MAP_VALUE, + + // flow map + ES_WAITING_FOR_FLOW_MAP_ENTRY, + ES_WAITING_FOR_FLOW_MAP_KEY, + ES_WRITING_FLOW_MAP_KEY, + ES_DONE_WITH_FLOW_MAP_KEY, + ES_WAITING_FOR_FLOW_MAP_VALUE, + ES_WRITING_FLOW_MAP_VALUE, + ES_DONE_WITH_FLOW_MAP_VALUE, + }; + + class EmitterState + { + public: + EmitterState(); + ~EmitterState(); + + // basic state checking + bool good() const { return m_isGood; } + const std::string GetLastError() const { return m_lastError; } + void SetError(const std::string& error) { m_isGood = false; m_lastError = error; } + + // main state of the machine + EMITTER_STATE GetCurState() const { return m_stateStack.top(); } + void SwitchState(EMITTER_STATE state) { PopState(); PushState(state); } + void PushState(EMITTER_STATE state) { m_stateStack.push(state); } + void PopState() { m_stateStack.pop(); } + + void SetLocalValue(EMITTER_MANIP value); + + // group handling + void BeginGroup(GROUP_TYPE type); + void EndGroup(GROUP_TYPE type); + + GROUP_TYPE GetCurGroupType() const; + FLOW_TYPE GetCurGroupFlowType() const; + int GetCurIndent() const { return m_curIndent; } + + bool CurrentlyInLongKey(); + void StartLongKey(); + void StartSimpleKey(); + + bool RequiresSeparation() const { return m_requiresSeparation; } + void RequireSeparation() { m_requiresSeparation = true; } + void UnsetSeparation() { m_requiresSeparation = false; } + + void ClearModifiedSettings(); + + // formatters + bool SetStringFormat(EMITTER_MANIP value, FMT_SCOPE scope); + EMITTER_MANIP GetStringFormat() const { return m_strFmt.get(); } + + bool SetBoolFormat(EMITTER_MANIP value, FMT_SCOPE scope); + EMITTER_MANIP GetBoolFormat() const { return m_boolFmt.get(); } + + bool SetBoolLengthFormat(EMITTER_MANIP value, FMT_SCOPE scope); + EMITTER_MANIP GetBoolLengthFormat() const { return m_boolLengthFmt.get(); } + + bool SetBoolCaseFormat(EMITTER_MANIP value, FMT_SCOPE scope); + EMITTER_MANIP GetBoolCaseFormat() const { return m_boolCaseFmt.get(); } + + bool SetIntFormat(EMITTER_MANIP value, FMT_SCOPE scope); + EMITTER_MANIP GetIntFormat() const { return m_intFmt.get(); } + + bool SetIndent(unsigned value, FMT_SCOPE scope); + int GetIndent() const { return m_indent.get(); } + + bool SetPreCommentIndent(unsigned value, FMT_SCOPE scope); + int GetPreCommentIndent() const { return m_preCommentIndent.get(); } + bool SetPostCommentIndent(unsigned value, FMT_SCOPE scope); + int GetPostCommentIndent() const { return m_postCommentIndent.get(); } + + bool SetFlowType(GROUP_TYPE groupType, EMITTER_MANIP value, FMT_SCOPE scope); + EMITTER_MANIP GetFlowType(GROUP_TYPE groupType) const; + + bool SetMapKeyFormat(EMITTER_MANIP value, FMT_SCOPE scope); + EMITTER_MANIP GetMapKeyFormat() const { return m_mapKeyFmt.get(); } + + private: + template + void _Set(Setting& fmt, T value, FMT_SCOPE scope); + + private: + // basic state ok? + bool m_isGood; + std::string m_lastError; + + // other state + std::stack m_stateStack; + + Setting m_strFmt; + Setting m_boolFmt; + Setting m_boolLengthFmt; + Setting m_boolCaseFmt; + Setting m_intFmt; + Setting m_indent; + Setting m_preCommentIndent, m_postCommentIndent; + Setting m_seqFmt; + Setting m_mapFmt; + Setting m_mapKeyFmt; + + SettingChanges m_modifiedSettings; + SettingChanges m_globalModifiedSettings; + + struct Group { + Group(GROUP_TYPE type_): type(type_), usingLongKey(false), indent(0) {} + + GROUP_TYPE type; + EMITTER_MANIP flow; + bool usingLongKey; + int indent; + + SettingChanges modifiedSettings; + }; + + std::auto_ptr _PopGroup(); + + std::stack m_groups; + unsigned m_curIndent; + bool m_requiresSeparation; + }; + + template + void EmitterState::_Set(Setting& fmt, T value, FMT_SCOPE scope) { + switch(scope) { + case LOCAL: + m_modifiedSettings.push(fmt.set(value)); + break; + case GLOBAL: + fmt.set(value); + m_globalModifiedSettings.push(fmt.set(value)); // this pushes an identity set, so when we restore, + // it restores to the value here, and not the previous one + break; + default: + assert(false); + } + } +} diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp new file mode 100644 index 0000000..1779a9b --- /dev/null +++ b/src/emitterutils.cpp @@ -0,0 +1,143 @@ +#include "emitterutils.h" +#include "exp.h" +#include "indentation.h" +#include "exceptions.h" +#include + +namespace YAML +{ + namespace Utils + { + namespace { + bool IsPrintable(char ch) { + return (0x20 <= ch && ch <= 0x7E); + } + + bool IsValidPlainScalar(const std::string& str, bool inFlow) { + // first check the start + const RegEx& start = (inFlow ? Exp::PlainScalarInFlow : Exp::PlainScalar); + if(!start.Matches(str)) + return false; + + // and check the end for plain whitespace (which can't be faithfully kept in a plain scalar) + if(!str.empty() && *str.rbegin() == ' ') + return false; + + // then check until something is disallowed + const RegEx& disallowed = (inFlow ? Exp::EndScalarInFlow : Exp::EndScalar) + || (Exp::BlankOrBreak + Exp::Comment) + || (!Exp::Printable) + || Exp::Break + || Exp::Tab; + Buffer buffer(&str[0], str.size()); + while(buffer.size) { + if(disallowed.Matches(buffer)) + return false; + ++buffer; + } + + return true; + } + } + + bool WriteString(ostream& out, const std::string& str, bool inFlow) + { + if(IsValidPlainScalar(str, inFlow)) { + out << str; + return true; + } else + return WriteDoubleQuotedString(out, str); + } + + bool WriteSingleQuotedString(ostream& out, const std::string& str) + { + out << "'"; + for(unsigned i=0;i(ch); + out << str.str(); + } + } + out << "\""; + return true; + } + + bool WriteLiteralString(ostream& out, const std::string& str, int indent) + { + out << "|\n"; + out << IndentTo(indent); + for(unsigned i=0;i + +namespace YAML +{ + namespace Utils + { + bool WriteString(ostream& out, const std::string& str, bool inFlow); + bool WriteSingleQuotedString(ostream& out, const std::string& str); + bool WriteDoubleQuotedString(ostream& out, const std::string& str); + bool WriteLiteralString(ostream& out, const std::string& str, int indent); + bool WriteComment(ostream& out, const std::string& str, int postCommentIndent); + bool WriteAlias(ostream& out, const std::string& str); + bool WriteAnchor(ostream& out, const std::string& str); + } +} diff --git a/src/exp.h b/src/exp.h index e878a80..12bd6ac 100644 --- a/src/exp.h +++ b/src/exp.h @@ -13,13 +13,16 @@ namespace YAML namespace Exp { // misc - const RegEx Blank = RegEx(' ') || RegEx('\t'); + const RegEx Space = RegEx(' '); + const RegEx Tab = RegEx('\t'); + const RegEx Blank = Space || Tab; const RegEx Break = RegEx('\n') || RegEx("\r\n"); const RegEx BlankOrBreak = Blank || Break; const RegEx Digit = RegEx('0', '9'); const RegEx Alpha = RegEx('a', 'z') || RegEx('A', 'Z'); const RegEx AlphaNumeric = Alpha || Digit; const RegEx Hex = Digit || RegEx('A', 'F') || RegEx('a', 'f'); + const RegEx Printable = RegEx(0x20, 0x7E); // actual tags diff --git a/src/indentation.h b/src/indentation.h new file mode 100644 index 0000000..b21412b --- /dev/null +++ b/src/indentation.h @@ -0,0 +1,30 @@ +#pragma once + +#include "ostream.h" +#include + +namespace YAML +{ + struct Indentation { + Indentation(unsigned n_): n(n_) {} + unsigned n; + }; + + inline ostream& operator << (ostream& out, const Indentation& indent) { + for(unsigned i=0;i + +namespace YAML +{ + ostream::ostream(): m_buffer(0), m_pos(0), m_size(0), m_row(0), m_col(0) + { + reserve(1024); + } + + ostream::~ostream() + { + delete [] m_buffer; + } + + void ostream::reserve(unsigned size) + { + if(size <= m_size) + return; + + char *newBuffer = new char[size]; + std::memset(newBuffer, 0, size * sizeof(char)); + std::memcpy(newBuffer, m_buffer, m_size * sizeof(char)); + delete [] m_buffer; + m_buffer = newBuffer; + m_size = size; + } + + void ostream::put(char ch) + { + if(m_pos >= m_size - 1) // an extra space for the NULL terminator + reserve(m_size * 2); + + m_buffer[m_pos] = ch; + m_pos++; + + if(ch == '\n') { + m_row++; + m_col = 0; + } else + m_col++; + } + + ostream& operator << (ostream& out, const char *str) + { + unsigned length = std::strlen(str); + for(unsigned i=0;i +#include +#include "noncopyable.h" + +namespace YAML +{ + class SettingChangeBase; + + template + class Setting + { + public: + Setting(): m_value() {} + + const T get() const { return m_value; } + std::auto_ptr set(const T& value); + void restore(const Setting& oldSetting) { + m_value = oldSetting.get(); + } + + private: + T m_value; + }; + + class SettingChangeBase + { + public: + virtual ~SettingChangeBase() {} + virtual void pop() = 0; + }; + + template + class SettingChange: public SettingChangeBase + { + public: + SettingChange(Setting *pSetting): m_pCurSetting(pSetting) { + // copy old setting to save its state + m_oldSetting = *pSetting; + } + + virtual void pop() { + m_pCurSetting->restore(m_oldSetting); + } + + private: + Setting *m_pCurSetting; + Setting m_oldSetting; + }; + + template + inline std::auto_ptr Setting::set(const T& value) { + std::auto_ptr pChange(new SettingChange (this)); + m_value = value; + return pChange; + } + + class SettingChanges: private noncopyable + { + public: + SettingChanges() {} + ~SettingChanges() { clear(); } + + void clear() { + restore(); + + for(setting_changes::const_iterator it=m_settingChanges.begin();it!=m_settingChanges.end();++it) + delete *it; + m_settingChanges.clear(); + } + + void restore() { + for(setting_changes::const_iterator it=m_settingChanges.begin();it!=m_settingChanges.end();++it) + (*it)->pop(); + } + + void push(std::auto_ptr pSettingChange) { + m_settingChanges.push_back(pSettingChange.release()); + } + + // like std::auto_ptr - assignment is transfer of ownership + SettingChanges& operator = (SettingChanges& rhs) { + if(this == &rhs) + return *this; + + clear(); + m_settingChanges = rhs.m_settingChanges; + rhs.m_settingChanges.clear(); + return *this; + } + + private: + typedef std::vector setting_changes; + setting_changes m_settingChanges; + }; +} diff --git a/src/stream.h b/src/stream.h index d35f3fe..5bc2c11 100644 --- a/src/stream.h +++ b/src/stream.h @@ -7,14 +7,15 @@ namespace YAML { // a simple buffer wrapper that knows how big it is struct Buffer { - Buffer(char *b, int s): buffer(b), size(s) {} + Buffer(const char *b, int s): buffer(b), size(s) {} operator bool() const { return size > 0; } bool operator !() const { return !static_cast (*this); } char operator [] (int i) const { return buffer[i]; } const Buffer operator + (int offset) const { return Buffer(buffer + offset, size - offset); } + Buffer& operator ++ () { ++buffer; --size; return *this; } - char *buffer; + const char *buffer; int size; }; diff --git a/yaml-reader/main.cpp b/yaml-reader/main.cpp index 00e47ed..b8e5ff7 100644 --- a/yaml-reader/main.cpp +++ b/yaml-reader/main.cpp @@ -4,6 +4,9 @@ #include #include +#include "emitter.h" +#include "stlemitter.h" + void run() { std::ifstream fin("tests/test.yaml"); @@ -15,6 +18,9 @@ void run() parser.GetNextDocument(doc); std::cout << doc; } + + // try some output + YAML::Emitter out; } int main(int argc, char **argv) diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp index 4f3ba6b..f7f1f5d 100644 --- a/yaml-reader/tests.cpp +++ b/yaml-reader/tests.cpp @@ -1,6 +1,9 @@ #include "yaml.h" #include "tests.h" #include "parser.h" +#include "emitter.h" +#include "stlemitter.h" +#include "exceptions.h" #include #include #include @@ -26,6 +29,9 @@ namespace Test } else std::cout << "Inout test passed: " << files[i] << "\n"; } + + if(!RunEmitterTests()) + passed = false; if(passed) std::cout << "All tests passed!\n"; @@ -86,4 +92,601 @@ namespace Test return true; } + + //////////////////////////////////////////////////////////////////////////////////////// + // Emitter tests + + namespace { + void RunTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, bool& passed) { + YAML::Emitter out; + std::string desiredOutput; + test(out, desiredOutput); + std::stringstream output; + out.WriteToStream(output); + + if(output.str() == desiredOutput) { + std::cout << "Test passed: " << name << "\n"; + } else { + passed = false; + std::cout << "Test failed: " << name << "\n"; + std::cout << "Output:\n"; + std::cout << output.str() << "<<<\n"; + std::cout << "Desired output:\n"; + std::cout << desiredOutput << "<<<\n"; + } + } + + void RunErrorTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, bool& passed) { + YAML::Emitter out; + std::string desiredError; + test(out, desiredError); + std::string lastError = out.GetLastError(); + if(!out.good() && lastError == desiredError) { + std::cout << "Test passed: " << name << "\n"; + } else { + passed = false; + std::cout << "Test failed: " << name << "\n"; + if(out.good()) + std::cout << "No error detected\n"; + else + std::cout << "Detected error: " << lastError << "\n"; + std::cout << "Expected error: " << desiredError << "\n"; + } + } + } + + bool RunEmitterTests() + { + bool passed = true; + RunTest(&Emitter::SimpleScalar, "simple scalar", passed); + RunTest(&Emitter::SimpleSeq, "simple seq", passed); + RunTest(&Emitter::SimpleFlowSeq, "simple flow seq", passed); + RunTest(&Emitter::EmptyFlowSeq, "empty flow seq", passed); + RunTest(&Emitter::NestedBlockSeq, "nested block seq", passed); + RunTest(&Emitter::NestedFlowSeq, "nested flow seq", passed); + RunTest(&Emitter::SimpleMap, "simple map", passed); + RunTest(&Emitter::SimpleFlowMap, "simple flow map", passed); + RunTest(&Emitter::MapAndList, "map and list", passed); + RunTest(&Emitter::ListAndMap, "list and map", passed); + RunTest(&Emitter::NestedBlockMap, "nested block map", passed); + RunTest(&Emitter::NestedFlowMap, "nested flow map", passed); + RunTest(&Emitter::MapListMix, "map list mix", passed); + RunTest(&Emitter::SimpleLongKey, "simple long key", passed); + RunTest(&Emitter::SingleLongKey, "single long key", passed); + RunTest(&Emitter::ComplexLongKey, "complex long key", passed); + RunTest(&Emitter::AutoLongKey, "auto long key", passed); + RunTest(&Emitter::ScalarFormat, "scalar format", passed); + RunTest(&Emitter::AutoLongKeyScalar, "auto long key scalar", passed); + RunTest(&Emitter::LongKeyFlowMap, "long key flow map", passed); + RunTest(&Emitter::BlockMapAsKey, "block map as key", passed); + RunTest(&Emitter::AliasAndAnchor, "alias and anchor", passed); + RunTest(&Emitter::ComplexDoc, "complex doc", passed); + RunTest(&Emitter::STLContainers, "STL containers", passed); + RunTest(&Emitter::SimpleComment, "simple comment", passed); + RunTest(&Emitter::MultiLineComment, "multi-line comment", passed); + RunTest(&Emitter::ComplexComments, "complex comments", passed); + RunTest(&Emitter::Indentation, "indentation", passed); + RunTest(&Emitter::SimpleGlobalSettings, "simple global settings", passed); + RunTest(&Emitter::ComplexGlobalSettings, "complex global settings", passed); + + RunErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed); + RunErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed); + RunErrorTest(&Emitter::BadSingleQuoted, "bad single quoted string", passed); + RunErrorTest(&Emitter::InvalidAnchor, "invalid anchor", passed); + RunErrorTest(&Emitter::InvalidAlias, "invalid alias", passed); + RunErrorTest(&Emitter::MissingKey, "missing key", passed); + RunErrorTest(&Emitter::MissingValue, "missing value", passed); + RunErrorTest(&Emitter::UnexpectedKey, "unexpected key", passed); + RunErrorTest(&Emitter::UnexpectedValue, "unexpected value", passed); + return passed; + } + + namespace Emitter { + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // correct emitting + + void SimpleScalar(YAML::Emitter& out, std::string& desiredOutput) { + out << "Hello, World!"; + desiredOutput = "Hello, World!"; + } + + void SimpleSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginSeq; + out << "eggs"; + out << "bread"; + out << "milk"; + out << YAML::EndSeq; + + desiredOutput = "- eggs\n- bread\n- milk"; + } + + void SimpleFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::Flow; + out << YAML::BeginSeq; + out << "Larry"; + out << "Curly"; + out << "Moe"; + out << YAML::EndSeq; + + desiredOutput = "[Larry, Curly, Moe]"; + } + + void EmptyFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::Flow; + out << YAML::BeginSeq; + out << YAML::EndSeq; + + desiredOutput = "[]"; + } + + void NestedBlockSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginSeq; + out << "item 1"; + out << YAML::BeginSeq << "subitem 1" << "subitem 2" << YAML::EndSeq; + out << YAML::EndSeq; + + desiredOutput = "- item 1\n-\n - subitem 1\n - subitem 2"; + } + + void NestedFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginSeq; + out << "one"; + out << YAML::Flow << YAML::BeginSeq << "two" << "three" << YAML::EndSeq; + out << YAML::EndSeq; + + desiredOutput = "- one\n- [two, three]"; + } + + void SimpleMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Ryan Braun"; + out << YAML::Key << "position"; + out << YAML::Value << "3B"; + out << YAML::EndMap; + + desiredOutput = "name: Ryan Braun\nposition: 3B"; + } + + void SimpleFlowMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::Flow; + out << YAML::BeginMap; + out << YAML::Key << "shape"; + out << YAML::Value << "square"; + out << YAML::Key << "color"; + out << YAML::Value << "blue"; + out << YAML::EndMap; + + desiredOutput = "{shape: square, color: blue}"; + } + + void MapAndList(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Barack Obama"; + out << YAML::Key << "children"; + out << YAML::Value << YAML::BeginSeq << "Sasha" << "Malia" << YAML::EndSeq; + out << YAML::EndMap; + + desiredOutput = "name: Barack Obama\nchildren:\n - Sasha\n - Malia"; + } + + void ListAndMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginSeq; + out << "item 1"; + out << YAML::BeginMap; + out << YAML::Key << "pens" << YAML::Value << 8; + out << YAML::Key << "pencils" << YAML::Value << 14; + out << YAML::EndMap; + out << "item 2"; + out << YAML::EndSeq; + + desiredOutput = "- item 1\n-\n pens: 8\n pencils: 14\n- item 2"; + } + + void NestedBlockMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Fred"; + out << YAML::Key << "grades"; + out << YAML::Value; + out << YAML::BeginMap; + out << YAML::Key << "algebra" << YAML::Value << "A"; + out << YAML::Key << "physics" << YAML::Value << "C+"; + out << YAML::Key << "literature" << YAML::Value << "B"; + out << YAML::EndMap; + out << YAML::EndMap; + + desiredOutput = "name: Fred\ngrades:\n algebra: A\n physics: C+\n literature: B"; + } + + void NestedFlowMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::Flow; + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Fred"; + out << YAML::Key << "grades"; + out << YAML::Value; + out << YAML::BeginMap; + out << YAML::Key << "algebra" << YAML::Value << "A"; + out << YAML::Key << "physics" << YAML::Value << "C+"; + out << YAML::Key << "literature" << YAML::Value << "B"; + out << YAML::EndMap; + out << YAML::EndMap; + + desiredOutput = "{name: Fred, grades: {algebra: A, physics: C+, literature: B}}"; + } + + void MapListMix(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Bob"; + out << YAML::Key << "position"; + out << YAML::Value; + out << YAML::Flow << YAML::BeginSeq << 2 << 4 << YAML::EndSeq; + out << YAML::Key << "invincible" << YAML::Value << YAML::OnOffBool << false; + out << YAML::EndMap; + + desiredOutput = "name: Bob\nposition: [2, 4]\ninvincible: off"; + } + + void SimpleLongKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::LongKey; + out << YAML::BeginMap; + out << YAML::Key << "height"; + out << YAML::Value << "5'9\""; + out << YAML::Key << "weight"; + out << YAML::Value << 145; + out << YAML::EndMap; + + desiredOutput = "? height\n: 5'9\"\n? weight\n: 145"; + } + + void SingleLongKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << "age"; + out << YAML::Value << "24"; + out << YAML::LongKey << YAML::Key << "height"; + out << YAML::Value << "5'9\""; + out << YAML::Key << "weight"; + out << YAML::Value << 145; + out << YAML::EndMap; + + desiredOutput = "age: 24\n? height\n: 5'9\"\nweight: 145"; + } + + void ComplexLongKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::LongKey; + out << YAML::BeginMap; + out << YAML::Key << YAML::BeginSeq << 1 << 3 << YAML::EndSeq; + out << YAML::Value << "monster"; + out << YAML::Key << YAML::Flow << YAML::BeginSeq << 2 << 0 << YAML::EndSeq; + out << YAML::Value << "demon"; + out << YAML::EndMap; + + desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon"; + } + + void AutoLongKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << YAML::BeginSeq << 1 << 3 << YAML::EndSeq; + out << YAML::Value << "monster"; + out << YAML::Key << YAML::Flow << YAML::BeginSeq << 2 << 0 << YAML::EndSeq; + out << YAML::Value << "demon"; + out << YAML::Key << "the origin"; + out << YAML::Value << "angel"; + out << YAML::EndMap; + + desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon\nthe origin: angel"; + } + + void ScalarFormat(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << "simple scalar"; + out << YAML::SingleQuoted << "explicit single-quoted scalar"; + out << YAML::DoubleQuoted << "explicit double-quoted scalar"; + out << "auto-detected\ndouble-quoted scalar"; + out << "a non-\"auto-detected\" double-quoted scalar"; + out << YAML::Literal << "literal scalar\nthat may span\nmany, many\nlines and have \"whatever\" crazy\tsymbols that we like"; + out << YAML::EndSeq; + + desiredOutput = "- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\xadouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like"; + } + + void AutoLongKeyScalar(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << YAML::Literal << "multi-line\nscalar"; + out << YAML::Value << "and its value"; + out << YAML::EndMap; + + desiredOutput = "? |\n multi-line\n scalar\n: and its value"; + } + + void LongKeyFlowMap(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Flow; + out << YAML::BeginMap; + out << YAML::Key << "simple key"; + out << YAML::Value << "and value"; + out << YAML::LongKey << YAML::Key << "long key"; + out << YAML::Value << "and its value"; + out << YAML::EndMap; + + desiredOutput = "{simple key: and value, ? long key: and its value}"; + } + + void BlockMapAsKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key; + out << YAML::BeginMap; + out << YAML::Key << "key" << YAML::Value << "value"; + out << YAML::Key << "next key" << YAML::Value << "next value"; + out << YAML::EndMap; + out << YAML::Value; + out << "total value"; + out << YAML::EndMap; + + desiredOutput = "?\n key: value\n next key: next value\n: total value"; + } + + void AliasAndAnchor(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << YAML::Anchor("fred"); + out << YAML::BeginMap; + out << YAML::Key << "name" << YAML::Value << "Fred"; + out << YAML::Key << "age" << YAML::Value << 42; + out << YAML::EndMap; + out << YAML::Alias("fred"); + out << YAML::EndSeq; + + desiredOutput = "- &fred\n name: Fred\n age: 42\n- *fred"; + } + + void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << "receipt"; + out << YAML::Value << "Oz-Ware Purchase Invoice"; + out << YAML::Key << "date"; + out << YAML::Value << "2007-08-06"; + out << YAML::Key << "customer"; + out << YAML::Value; + out << YAML::BeginMap; + out << YAML::Key << "given"; + out << YAML::Value << "Dorothy"; + out << YAML::Key << "family"; + out << YAML::Value << "Gale"; + out << YAML::EndMap; + out << YAML::Key << "items"; + out << YAML::Value; + out << YAML::BeginSeq; + out << YAML::BeginMap; + out << YAML::Key << "part_no"; + out << YAML::Value << "A4786"; + out << YAML::Key << "descrip"; + out << YAML::Value << "Water Bucket (Filled)"; + out << YAML::Key << "price"; + out << YAML::Value << 1.47; + out << YAML::Key << "quantity"; + out << YAML::Value << 4; + out << YAML::EndMap; + out << YAML::BeginMap; + out << YAML::Key << "part_no"; + out << YAML::Value << "E1628"; + out << YAML::Key << "descrip"; + out << YAML::Value << "High Heeled \"Ruby\" Slippers"; + out << YAML::Key << "price"; + out << YAML::Value << 100.27; + out << YAML::Key << "quantity"; + out << YAML::Value << 1; + out << YAML::EndMap; + out << YAML::EndSeq; + out << YAML::Key << "bill-to"; + out << YAML::Value << YAML::Anchor("id001"); + out << YAML::BeginMap; + out << YAML::Key << "street"; + out << YAML::Value << YAML::Literal << "123 Tornado Alley\nSuite 16"; + out << YAML::Key << "city"; + out << YAML::Value << "East Westville"; + out << YAML::Key << "state"; + out << YAML::Value << "KS"; + out << YAML::EndMap; + out << YAML::Key << "ship-to"; + out << YAML::Value << YAML::Alias("id001"); + out << YAML::EndMap; + + desiredOutput = "receipt: Oz-Ware Purchase Invoice\ndate: 2007-08-06\ncustomer:\n given: Dorothy\n family: Gale\nitems:\n -\n part_no: A4786\n descrip: Water Bucket (Filled)\n price: 1.47\n quantity: 4\n -\n part_no: E1628\n descrip: High Heeled \"Ruby\" Slippers\n price: 100.27\n quantity: 1\nbill-to: &id001\n street: |\n 123 Tornado Alley\n Suite 16\n city: East Westville\n state: KS\nship-to: *id001"; + } + + void STLContainers(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + std::vector primes; + primes.push_back(2); + primes.push_back(3); + primes.push_back(5); + primes.push_back(7); + primes.push_back(11); + primes.push_back(13); + out << YAML::Flow << primes; + std::map ages; + ages["Daniel"] = 26; + ages["Jesse"] = 24; + out << ages; + out << YAML::EndSeq; + + desiredOutput = "- [2, 3, 5, 7, 11, 13]\n-\n Daniel: 26\n Jesse: 24"; + } + + void SimpleComment(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << "method"; + out << YAML::Value << "least squares" << YAML::Comment("should we change this method?"); + out << YAML::EndMap; + + desiredOutput = "method: least squares # should we change this method?"; + } + + void MultiLineComment(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << "item 1" << YAML::Comment("really really long\ncomment that couldn't possibly\nfit on one line"); + out << "item 2"; + out << YAML::EndSeq; + + desiredOutput = "- item 1 # really really long\n # comment that couldn't possibly\n # fit on one line\n- item 2"; + } + + void ComplexComments(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::LongKey << YAML::Key << "long key" << YAML::Comment("long key"); + out << YAML::Value << "value"; + out << YAML::EndMap; + + desiredOutput = "? long key # long key\n: value"; + } + + void Indentation(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Indent(4); + out << YAML::BeginSeq; + out << YAML::BeginMap; + out << YAML::Key << "key 1" << YAML::Value << "value 1"; + out << YAML::Key << "key 2" << YAML::Value << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; + out << YAML::EndMap; + out << YAML::EndSeq; + + desiredOutput = "-\n key 1: value 1\n key 2:\n - a\n - b\n - c"; + } + + void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) + { + out.SetIndent(4); + out.SetMapFormat(YAML::LongKey); + + out << YAML::BeginSeq; + out << YAML::BeginMap; + out << YAML::Key << "key 1" << YAML::Value << "value 1"; + out << YAML::Key << "key 2" << YAML::Value << YAML::Flow << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; + out << YAML::EndMap; + out << YAML::EndSeq; + + desiredOutput = "-\n ? key 1\n : value 1\n ? key 2\n : [a, b, c]"; + } + + void ComplexGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << YAML::Block; + out << YAML::BeginMap; + out << YAML::Key << "key 1" << YAML::Value << "value 1"; + out << YAML::Key << "key 2" << YAML::Value; + out.SetSeqFormat(YAML::Flow); + out << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; + out << YAML::EndMap; + out << YAML::BeginMap; + out << YAML::Key << YAML::BeginSeq << 1 << 2 << YAML::EndSeq; + out << YAML::Value << YAML::BeginMap << YAML::Key << "a" << YAML::Value << "b" << YAML::EndMap; + out << YAML::EndMap; + out << YAML::EndSeq; + + desiredOutput = "-\n key 1: value 1\n key 2: [a, b, c]\n-\n ? [1, 2]\n :\n a: b"; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // incorrect emitting + + void ExtraEndSeq(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::UNEXPECTED_END_SEQ; + + out << YAML::BeginSeq; + out << "Hello"; + out << "World"; + out << YAML::EndSeq; + out << YAML::EndSeq; + } + + void ExtraEndMap(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::UNEXPECTED_END_MAP; + + out << YAML::BeginMap; + out << YAML::Key << "Hello" << YAML::Value << "World"; + out << YAML::EndMap; + out << YAML::EndMap; + } + + void BadSingleQuoted(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::SINGLE_QUOTED_CHAR; + + out << YAML::SingleQuoted << "Hello\nWorld"; + } + + void InvalidAnchor(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::INVALID_ANCHOR; + + out << YAML::BeginSeq; + out << YAML::Anchor("new\nline") << "Test"; + out << YAML::EndSeq; + } + + void InvalidAlias(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::INVALID_ALIAS; + + out << YAML::BeginSeq; + out << YAML::Alias("new\nline"); + out << YAML::EndSeq; + } + + void MissingKey(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::EXPECTED_KEY_TOKEN; + + out << YAML::BeginMap; + out << YAML::Key << "key" << YAML::Value << "value"; + out << "missing key" << YAML::Value << "value"; + out << YAML::EndMap; + } + + void MissingValue(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::EXPECTED_VALUE_TOKEN; + + out << YAML::BeginMap; + out << YAML::Key << "key" << "value"; + out << YAML::EndMap; + } + + void UnexpectedKey(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::UNEXPECTED_KEY_TOKEN; + + out << YAML::BeginSeq; + out << YAML::Key << "hi"; + out << YAML::EndSeq; + } + + void UnexpectedValue(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::UNEXPECTED_VALUE_TOKEN; + + out << YAML::BeginSeq; + out << YAML::Value << "hi"; + out << YAML::EndSeq; + } + } } diff --git a/yaml-reader/tests.h b/yaml-reader/tests.h index c615b24..a062a09 100644 --- a/yaml-reader/tests.h +++ b/yaml-reader/tests.h @@ -1,6 +1,55 @@ #include +namespace YAML { class Emitter; } + namespace Test { void RunAll(bool verbose); bool Inout(const std::string& file, bool verbose); + + bool RunEmitterTests(); + + namespace Emitter { + // correct emitting + void SimpleScalar(YAML::Emitter& out, std::string& desiredOutput); + void SimpleSeq(YAML::Emitter& out, std::string& desiredOutput); + void SimpleFlowSeq(YAML::Emitter& ouptut, std::string& desiredOutput); + void EmptyFlowSeq(YAML::Emitter& out, std::string& desiredOutput); + void NestedBlockSeq(YAML::Emitter& out, std::string& desiredOutput); + void NestedFlowSeq(YAML::Emitter& out, std::string& desiredOutput); + void SimpleMap(YAML::Emitter& out, std::string& desiredOutput); + void SimpleFlowMap(YAML::Emitter& out, std::string& desiredOutput); + void MapAndList(YAML::Emitter& out, std::string& desiredOutput); + void ListAndMap(YAML::Emitter& out, std::string& desiredOutput); + void NestedBlockMap(YAML::Emitter& out, std::string& desiredOutput); + void NestedFlowMap(YAML::Emitter& out, std::string& desiredOutput); + void MapListMix(YAML::Emitter& out, std::string& desiredOutput); + void SimpleLongKey(YAML::Emitter& out, std::string& desiredOutput); + void SingleLongKey(YAML::Emitter& out, std::string& desiredOutput); + void ComplexLongKey(YAML::Emitter& out, std::string& desiredOutput); + void AutoLongKey(YAML::Emitter& out, std::string& desiredOutput); + void ScalarFormat(YAML::Emitter& out, std::string& desiredOutput); + void AutoLongKeyScalar(YAML::Emitter& out, std::string& desiredOutput); + void LongKeyFlowMap(YAML::Emitter& out, std::string& desiredOutput); + void BlockMapAsKey(YAML::Emitter& out, std::string& desiredOutput); + void AliasAndAnchor(YAML::Emitter& out, std::string& desiredOutput); + void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput); + void STLContainers(YAML::Emitter& out, std::string& desiredOutput); + void SimpleComment(YAML::Emitter& out, std::string& desiredOutput); + void MultiLineComment(YAML::Emitter& out, std::string& desiredOutput); + void ComplexComments(YAML::Emitter& out, std::string& desiredOutput); + void Indentation(YAML::Emitter& out, std::string& desiredOutput); + void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput); + void ComplexGlobalSettings(YAML::Emitter& out, std::string& desiredOutput); + + // incorrect emitting + void ExtraEndSeq(YAML::Emitter& out, std::string& desiredError); + void ExtraEndMap(YAML::Emitter& out, std::string& desiredError); + void BadSingleQuoted(YAML::Emitter& out, std::string& desiredError); + void InvalidAnchor(YAML::Emitter& out, std::string& desiredError); + void InvalidAlias(YAML::Emitter& out, std::string& desiredError); + void MissingKey(YAML::Emitter& out, std::string& desiredError); + void MissingValue(YAML::Emitter& out, std::string& desiredError); + void UnexpectedKey(YAML::Emitter& out, std::string& desiredError); + void UnexpectedValue(YAML::Emitter& out, std::string& desiredError); + } } From e6617e3273985bcaad82103f86d72ed0bdbd3f54 Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 22 May 2009 21:56:45 +0000 Subject: [PATCH 088/295] Removed excessive stderr logging --- src/emitter.cpp | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/emitter.cpp b/src/emitter.cpp index bdc2fba..3db240f 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -147,39 +147,31 @@ namespace YAML switch(curState) { // document-level case ES_WAITING_FOR_DOC: - std::cerr << "waiting for doc (pre)\n"; m_pState->SwitchState(ES_WRITING_DOC); return true; case ES_WRITING_DOC: - std::cerr << "writing doc (pre)\n"; return true; // block sequence case ES_WAITING_FOR_BLOCK_SEQ_ENTRY: - std::cerr << "waiting for block seq entry (pre)\n"; m_stream << IndentTo(curIndent) << "-"; m_pState->RequireSeparation(); m_pState->SwitchState(ES_WRITING_BLOCK_SEQ_ENTRY); return true; case ES_WRITING_BLOCK_SEQ_ENTRY: - std::cerr << "writing block seq entry (pre)\n"; return true; case ES_DONE_WITH_BLOCK_SEQ_ENTRY: - std::cerr << "done with block seq entry (pre)\n"; m_stream << '\n'; m_pState->SwitchState(ES_WAITING_FOR_BLOCK_SEQ_ENTRY); return false; // flow sequence case ES_WAITING_FOR_FLOW_SEQ_ENTRY: - std::cerr << "waiting for flow seq entry (pre)\n"; m_pState->SwitchState(ES_WRITING_FLOW_SEQ_ENTRY); return true; case ES_WRITING_FLOW_SEQ_ENTRY: - std::cerr << "writing flow seq entry (pre)\n"; return true; case ES_DONE_WITH_FLOW_SEQ_ENTRY: - std::cerr << "done with flow seq entry (pre)\n"; m_stream << ','; m_pState->RequireSeparation(); m_pState->SwitchState(ES_WAITING_FOR_FLOW_SEQ_ENTRY); @@ -187,11 +179,9 @@ namespace YAML // block map case ES_WAITING_FOR_BLOCK_MAP_ENTRY: - std::cerr << "waiting for block map entry (pre)\n"; m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN); return true; case ES_WAITING_FOR_BLOCK_MAP_KEY: - std::cerr << "waiting for block map key (pre)\n"; if(m_pState->CurrentlyInLongKey()) { m_stream << IndentTo(curIndent) << '?'; m_pState->RequireSeparation(); @@ -199,14 +189,11 @@ namespace YAML m_pState->SwitchState(ES_WRITING_BLOCK_MAP_KEY); return true; case ES_WRITING_BLOCK_MAP_KEY: - std::cerr << "writing block map key (pre)\n"; return true; case ES_DONE_WITH_BLOCK_MAP_KEY: - std::cerr << "done with block map key (pre)\n"; m_pState->SetError(ErrorMsg::EXPECTED_VALUE_TOKEN); return true; case ES_WAITING_FOR_BLOCK_MAP_VALUE: - std::cerr << "waiting for block map value (pre)\n"; if(m_pState->CurrentlyInLongKey()) m_stream << IndentTo(curIndent); m_stream << ':'; @@ -214,20 +201,16 @@ namespace YAML m_pState->SwitchState(ES_WRITING_BLOCK_MAP_VALUE); return true; case ES_WRITING_BLOCK_MAP_VALUE: - std::cerr << "writing block map value (pre)\n"; return true; case ES_DONE_WITH_BLOCK_MAP_VALUE: - std::cerr << "done with block map value (pre)\n"; m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN); return true; // flow map case ES_WAITING_FOR_FLOW_MAP_ENTRY: - std::cerr << "waiting for flow map entry (pre)\n"; m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN); return true; case ES_WAITING_FOR_FLOW_MAP_KEY: - std::cerr << "waiting for flow map key (pre)\n"; m_pState->SwitchState(ES_WRITING_FLOW_MAP_KEY); if(m_pState->CurrentlyInLongKey()) { EmitSeparationIfNecessary(); @@ -236,23 +219,18 @@ namespace YAML } return true; case ES_WRITING_FLOW_MAP_KEY: - std::cerr << "writing flow map key (pre)\n"; return true; case ES_DONE_WITH_FLOW_MAP_KEY: - std::cerr << "done with flow map key (pre)\n"; m_pState->SetError(ErrorMsg::EXPECTED_VALUE_TOKEN); return true; case ES_WAITING_FOR_FLOW_MAP_VALUE: - std::cerr << "waiting for flow map value (pre)\n"; m_stream << ':'; m_pState->RequireSeparation(); m_pState->SwitchState(ES_WRITING_FLOW_MAP_VALUE); return true; case ES_WRITING_FLOW_MAP_VALUE: - std::cerr << "writing flow map value (pre)\n"; return true; case ES_DONE_WITH_FLOW_MAP_VALUE: - std::cerr << "done with flow map value (pre)\n"; m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN); return true; default: From 3e41edd30ee4a8ee12f016b5c34045c212037683 Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 22 May 2009 22:11:21 +0000 Subject: [PATCH 089/295] Restructured CMake file to include headers, and to be better organized --- CMakeLists.txt | 69 +++++++++++++++++++++++++++++++++++++++++++++- src/CMakeLists.txt | 9 ------ 2 files changed, 68 insertions(+), 10 deletions(-) delete mode 100644 src/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 789f731..e4461c7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,71 @@ +cmake_minimum_required(VERSION 2.6) + project (YAML_CPP) set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) -add_subdirectory (src) + +set(PUB_HDR + include/crt.h + include/emitter.h + include/emittermanip.h + include/exceptions.h + include/iterator.h + include/node.h + include/noncopyable.h + include/ostream.h + include/parser.h + include/parserstate.h + include/stlemitter.h + include/yaml.h +) + +set(PVT_HDR + src/alias.h + src/content.h + src/emitterstate.h + src/emitterutils.h + src/exp.h + src/indentation.h + src/iterpriv.h + src/ltnode.h + src/map.h + src/regex.h + src/scalar.h + src/scanner.h + src/scanscalar.h + src/sequence.h + src/setting.h + src/stream.h + src/token.h +) + +set(SRC + src/alias.cpp + src/content.cpp + src/emitter.cpp + src/emitterstate.cpp + src/emitterutils.cpp + src/exp.cpp + src/iterator.cpp + src/map.cpp + src/node.cpp + src/ostream.cpp + src/parser.cpp + src/parserstate.cpp + src/regex.cpp + src/scalar.cpp + src/scanner.cpp + src/scanscalar.cpp + src/scantoken.cpp + src/sequence.cpp + src/simplekey.cpp + src/stream.cpp +) + +include_directories(${YAML_CPP_SOURCE_DIR}/include) +add_library(yaml-cpp + ${PUB_HDR} + ${PVT_HDR} + ${SRC} +) + add_subdirectory (yaml-reader) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index 8e59ffe..0000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -set(FILES alias.cpp content.cpp iterator.cpp node.cpp parserstate.cpp - scalar.cpp scanscalar.cpp sequence.cpp stream.cpp - exp.cpp map.cpp parser.cpp regex.cpp scanner.cpp - scantoken.cpp simplekey.cpp - emitter.cpp emitterstate.h emitterstate.cpp emitterutils.h emitterutils.cpp - ostream.cpp) - -include_directories(${YAML_CPP_SOURCE_DIR}/include) -add_library(yaml-cpp ${FILES}) From 7dd29ee5db996aede930659a027f866bcc300e0a Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 22 May 2009 22:21:01 +0000 Subject: [PATCH 090/295] Replaced direct emitter writing with an accessor to a C-string --- include/emitter.h | 5 +++-- include/ostream.h | 1 + src/emitter.cpp | 14 ++++---------- yaml-reader/tests.cpp | 7 +++---- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/include/emitter.h b/include/emitter.h index 92d9993..dce2666 100644 --- a/include/emitter.h +++ b/include/emitter.h @@ -15,8 +15,9 @@ namespace YAML Emitter(); ~Emitter(); - bool WriteToStream(std::ostream& out) const; - bool WriteToFile(const std::string& fileName) const; + // output + const char *c_str() const; + unsigned size() const; // state checking bool good() const; diff --git a/include/ostream.h b/include/ostream.h index 5051576..4936c44 100644 --- a/include/ostream.h +++ b/include/ostream.h @@ -16,6 +16,7 @@ namespace YAML unsigned row() const { return m_row; } unsigned col() const { return m_col; } + unsigned pos() const { return m_pos; } private: char *m_buffer; diff --git a/src/emitter.cpp b/src/emitter.cpp index 3db240f..15df4e8 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -3,7 +3,6 @@ #include "emitterutils.h" #include "indentation.h" #include "exceptions.h" -#include #include namespace YAML @@ -16,19 +15,14 @@ namespace YAML { } - bool Emitter::WriteToStream(std::ostream& out) const + const char *Emitter::c_str() const { - out << m_stream.str(); - return true; + return m_stream.str(); } - bool Emitter::WriteToFile(const std::string& fileName) const + unsigned Emitter::size() const { - std::ofstream fout(fileName.c_str()); - if(!fout) - return false; - - return WriteToStream(fout); + return m_stream.pos(); } // state checking diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp index f7f1f5d..f868beb 100644 --- a/yaml-reader/tests.cpp +++ b/yaml-reader/tests.cpp @@ -101,16 +101,15 @@ namespace Test YAML::Emitter out; std::string desiredOutput; test(out, desiredOutput); - std::stringstream output; - out.WriteToStream(output); + std::string output = out.c_str(); - if(output.str() == desiredOutput) { + if(output == desiredOutput) { std::cout << "Test passed: " << name << "\n"; } else { passed = false; std::cout << "Test failed: " << name << "\n"; std::cout << "Output:\n"; - std::cout << output.str() << "<<<\n"; + std::cout << output << "<<<\n"; std::cout << "Desired output:\n"; std::cout << desiredOutput << "<<<\n"; } From fcab73a9b60f515f63b0671d191040dd0103bff7 Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 22 May 2009 22:23:57 +0000 Subject: [PATCH 091/295] Added emitter headers to yaml.h --- include/yaml.h | 3 ++- yaml-reader/main.cpp | 3 --- yaml-reader/tests.cpp | 4 ---- 3 files changed, 2 insertions(+), 8 deletions(-) diff --git a/include/yaml.h b/include/yaml.h index f7cd1e7..b17868e 100644 --- a/include/yaml.h +++ b/include/yaml.h @@ -4,5 +4,6 @@ #include "parser.h" #include "node.h" #include "iterator.h" +#include "emitter.h" +#include "stlemitter.h" #include "exceptions.h" - diff --git a/yaml-reader/main.cpp b/yaml-reader/main.cpp index b8e5ff7..7cf8a26 100644 --- a/yaml-reader/main.cpp +++ b/yaml-reader/main.cpp @@ -4,9 +4,6 @@ #include #include -#include "emitter.h" -#include "stlemitter.h" - void run() { std::ifstream fin("tests/test.yaml"); diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp index f868beb..3bcb6b9 100644 --- a/yaml-reader/tests.cpp +++ b/yaml-reader/tests.cpp @@ -1,9 +1,5 @@ #include "yaml.h" #include "tests.h" -#include "parser.h" -#include "emitter.h" -#include "stlemitter.h" -#include "exceptions.h" #include #include #include From 947356a64a2d5e068b45b5735743fcf8be49e846 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sat, 23 May 2009 17:11:19 +0000 Subject: [PATCH 092/295] Changed output library directory to /lib (in the source directory) - this makes more sense --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e4461c7..50df2fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 2.6) project (YAML_CPP) -set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) +set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) set(PUB_HDR include/crt.h From 0c34137d841d8b6efe397cce5b76d0ae1983a8fd Mon Sep 17 00:00:00 2001 From: jbeder Date: Sat, 23 May 2009 22:58:05 +0000 Subject: [PATCH 093/295] Updated Visual Studio project for the emitter. --- yamlcpp.vcproj | 66 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 5 deletions(-) diff --git a/yamlcpp.vcproj b/yamlcpp.vcproj index 3450b7b..5c662ae 100644 --- a/yamlcpp.vcproj +++ b/yamlcpp.vcproj @@ -167,9 +167,9 @@ - + + + + + + + + + + + + + + + @@ -261,8 +289,8 @@ - + + + + + + + + + + + + + + Date: Sat, 23 May 2009 23:51:01 +0000 Subject: [PATCH 094/295] Changed the way we read different types of scalars. It's better organized now, I think - nodes only offer a single main way of getting the fundamental scalar (as a string), and now we can specialize a single template to read specific types. --- CMakeLists.txt | 2 + include/conversion.h | 35 ++++++++++ include/node.h | 27 ++++---- src/alias.cpp | 39 +---------- src/alias.h | 9 +-- src/content.h | 9 +-- src/conversion.cpp | 86 +++++++++++++++++++++++++ src/node.cpp | 68 +------------------- src/scalar.cpp | 125 ------------------------------------ src/scalar.h | 12 ++-- yaml-reader/tests/test.yaml | 6 +- yamlcpp.vcproj | 10 ++- 12 files changed, 158 insertions(+), 270 deletions(-) create mode 100644 include/conversion.h create mode 100644 src/conversion.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 50df2fa..287677d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,7 @@ project (YAML_CPP) set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) set(PUB_HDR + include/conversion.h include/crt.h include/emitter.h include/emittermanip.h @@ -41,6 +42,7 @@ set(PVT_HDR set(SRC src/alias.cpp src/content.cpp + src/conversion.cpp src/emitter.cpp src/emitterstate.cpp src/emitterutils.cpp diff --git a/include/conversion.h b/include/conversion.h new file mode 100644 index 0000000..12f688c --- /dev/null +++ b/include/conversion.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include + +namespace YAML +{ + template + struct Converter { + static bool Convert(const std::string& input, T& output); + }; + + template + bool Convert(const std::string& input, T& output) { + return Converter::Convert(input, output); + } + + // this is the one to specialize + template + inline bool Converter::Convert(const std::string& input, T& output) { + std::stringstream stream(input); + stream >> output; + return !stream.fail(); + } + + // specializations + template <> + inline bool Converter::Convert(const std::string& input, std::string& output) { + output = input; + return true; + } + + template <> + bool Converter::Convert(const std::string& input, bool& output); +} diff --git a/include/node.h b/include/node.h index 0dcac18..1b1530f 100644 --- a/include/node.h +++ b/include/node.h @@ -7,6 +7,7 @@ #include "parserstate.h" #include "exceptions.h" #include "iterator.h" +#include "conversion.h" namespace YAML { @@ -37,18 +38,11 @@ namespace YAML unsigned size() const; // extraction of scalars - bool Read(std::string& s) const; - bool Read(int& i) const; - bool Read(unsigned& u) const; - bool Read(long& l) const; - bool Read(float& f) const; - bool Read(double& d) const; - bool Read(char& c) const; - bool Read(bool& b) const; + bool GetScalar(std::string& s) const; - // so you can specialize for other values + // we can specialize this for other values template - friend bool Read(const Node& node, T& value); + bool Read(T& value) const; template friend void operator >> (const Node& node, T& value); @@ -100,15 +94,18 @@ namespace YAML // templated things we need to keep inline in the header template - inline bool Read(const Node& node, T& value) - { - return node.Read(value); + inline bool Node::Read(T& value) const { + std::string scalar; + if(!GetScalar(scalar)) + return false; + + return Convert(scalar, value); } template inline void operator >> (const Node& node, T& value) { - if(!Read(node, value)) + if(!node.Read(value)) throw InvalidScalar(node.m_line, node.m_column); } @@ -120,7 +117,7 @@ namespace YAML for(Iterator it=begin();it!=end();++it) { T t; - if(YAML::Read(it.first(), t)) { + if(it.first().Read(t)) { if(key == t) return it.second(); } diff --git a/src/alias.cpp b/src/alias.cpp index e8a4560..ae349cf 100644 --- a/src/alias.cpp +++ b/src/alias.cpp @@ -63,44 +63,9 @@ namespace YAML return m_pRef->IsSequence(); } - bool Alias::Read(std::string& v) const + bool Alias::GetScalar(std::string& scalar) const { - return m_pRef->Read(v); - } - - bool Alias::Read(int& v) const - { - return m_pRef->Read(v); - } - - bool Alias::Read(unsigned& v) const - { - return m_pRef->Read(v); - } - - bool Alias::Read(long& v) const - { - return m_pRef->Read(v); - } - - bool Alias::Read(float& v) const - { - return m_pRef->Read(v); - } - - bool Alias::Read(double& v) const - { - return m_pRef->Read(v); - } - - bool Alias::Read(char& v) const - { - return m_pRef->Read(v); - } - - bool Alias::Read(bool& v) const - { - return m_pRef->Read(v); + return m_pRef->GetScalar(scalar); } int Alias::Compare(Content *pContent) diff --git a/src/alias.h b/src/alias.h index 2f15d67..ad80b79 100644 --- a/src/alias.h +++ b/src/alias.h @@ -22,14 +22,7 @@ namespace YAML virtual bool IsMap() const; virtual bool IsSequence() const; - virtual bool Read(std::string&) const; - virtual bool Read(int&) const; - virtual bool Read(unsigned&) const; - virtual bool Read(long&) const; - virtual bool Read(float&) const; - virtual bool Read(double&) const; - virtual bool Read(char&) const; - virtual bool Read(bool&) const; + virtual bool GetScalar(std::string& s) const; virtual int Compare(Content *); virtual int Compare(Scalar *); diff --git a/src/content.h b/src/content.h index f689cd6..6399682 100644 --- a/src/content.h +++ b/src/content.h @@ -36,14 +36,7 @@ namespace YAML virtual bool IsSequence() const { return false; } // extraction - virtual bool Read(std::string&) const { return false; } - virtual bool Read(int&) const { return false; } - virtual bool Read(unsigned&) const { return false; } - virtual bool Read(long&) const { return false; } - virtual bool Read(float&) const { return false; } - virtual bool Read(double&) const { return false; } - virtual bool Read(char&) const { return false; } - virtual bool Read(bool&) const { return false; } + virtual bool GetScalar(std::string&) const { return false; } // ordering virtual int Compare(Content *) { return 0; } diff --git a/src/conversion.cpp b/src/conversion.cpp new file mode 100644 index 0000000..b990314 --- /dev/null +++ b/src/conversion.cpp @@ -0,0 +1,86 @@ +#include "conversion.h" +#include + + +//////////////////////////////////////////////////////////////// +// Specializations for converting a string to specific types + +namespace +{ + // we're not gonna mess with the mess that is all the isupper/etc. functions + bool IsLower(char ch) { return 'a' <= ch && ch <= 'z'; } + bool IsUpper(char ch) { return 'A' <= ch && ch <= 'Z'; } + char ToLower(char ch) { return IsUpper(ch) ? ch + 'a' - 'A' : ch; } + + std::string tolower(const std::string& str) + { + std::string s(str); + std::transform(s.begin(), s.end(), s.begin(), ToLower); + return s; + } + + template + bool IsEntirely(const std::string& str, T func) + { + for(unsigned i=0;i + bool Converter::Convert(const std::string& input, bool& b) + { + // we can't use iostream bool extraction operators as they don't + // recognize all possible values in the table below (taken from + // http://yaml.org/type/bool.html) + static const struct { + std::string truename, falsename; + } names[] = { + { "y", "n" }, + { "yes", "no" }, + { "true", "false" }, + { "on", "off" }, + }; + + if(!IsFlexibleCase(input)) + return false; + + for(unsigned i=0;iRead(s); - } - - bool Node::Read(int& i) const - { - if(!m_pContent) - return false; - - return m_pContent->Read(i); - } - - bool Node::Read(unsigned& u) const - { - if(!m_pContent) - return false; - - return m_pContent->Read(u); - } - - bool Node::Read(long& l) const - { - if(!m_pContent) - return false; - - return m_pContent->Read(l); - } - - bool Node::Read(float& f) const - { - if(!m_pContent) - return false; - - return m_pContent->Read(f); - } - - bool Node::Read(double& d) const - { - if(!m_pContent) - return false; - - return m_pContent->Read(d); - } - - bool Node::Read(char& c) const - { - if(!m_pContent) - return false; - - return m_pContent->Read(c); - } - - bool Node::Read(bool& b) const - { - if(!m_pContent) - return false; - - return m_pContent->Read(b); + return m_pContent->GetScalar(s); } std::ostream& operator << (std::ostream& out, const Node& node) diff --git a/src/scalar.cpp b/src/scalar.cpp index 03dfa4b..34e8280 100644 --- a/src/scalar.cpp +++ b/src/scalar.cpp @@ -4,8 +4,6 @@ #include "token.h" #include "exceptions.h" #include "node.h" -#include -#include namespace YAML { @@ -39,129 +37,6 @@ namespace YAML out << "\"\n"; } - bool Scalar::Read(std::string& s) const - { - s = m_data; - return true; - } - - bool Scalar::Read(int& i) const - { - std::stringstream data(m_data); - data >> i; - return !data.fail(); - } - - bool Scalar::Read(unsigned& u) const - { - std::stringstream data(m_data); - data >> u; - return !data.fail(); - } - - bool Scalar::Read(long& l) const - { - std::stringstream data(m_data); - data >> l; - return !data.fail(); - } - - bool Scalar::Read(float& f) const - { - std::stringstream data(m_data); - data >> f; - return !data.fail(); - } - - bool Scalar::Read(double& d) const - { - std::stringstream data(m_data); - data >> d; - return !data.fail(); - } - - bool Scalar::Read(char& c) const - { - std::stringstream data(m_data); - data >> c; - return !data.fail(); - } - - namespace - { - // we're not gonna mess with the mess that is all the isupper/etc. functions - bool IsLower(char ch) { return 'a' <= ch && ch <= 'z'; } - bool IsUpper(char ch) { return 'A' <= ch && ch <= 'Z'; } - char ToLower(char ch) { return IsUpper(ch) ? ch + 'a' - 'A' : ch; } - - std::string tolower(const std::string& str) - { - std::string s(str); - std::transform(s.begin(), s.end(), s.begin(), ToLower); - return s; - } - - template - bool IsEntirely(const std::string& str, T func) - { - for(unsigned i=0;iCompare(this); diff --git a/src/scalar.h b/src/scalar.h index b6a606d..e27d17e 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -17,14 +17,10 @@ namespace YAML virtual bool IsScalar() const { return true; } // extraction - virtual bool Read(std::string& s) const; - virtual bool Read(int& i) const; - virtual bool Read(unsigned& u) const; - virtual bool Read(long& l) const; - virtual bool Read(float& f) const; - virtual bool Read(double& d) const; - virtual bool Read(char& c) const; - virtual bool Read(bool& b) const; + virtual bool GetScalar(std::string& scalar) const { + scalar = m_data; + return true; + } // ordering virtual int Compare(Content *pContent); diff --git a/yaml-reader/tests/test.yaml b/yaml-reader/tests/test.yaml index 00e30f5..c914749 100644 --- a/yaml-reader/tests/test.yaml +++ b/yaml-reader/tests/test.yaml @@ -1,2 +1,4 @@ ---- -... \ No newline at end of file +- true +- false +- y +- n \ No newline at end of file diff --git a/yamlcpp.vcproj b/yamlcpp.vcproj index 5c662ae..53d6f37 100644 --- a/yamlcpp.vcproj +++ b/yamlcpp.vcproj @@ -175,6 +175,10 @@ RelativePath=".\src\content.cpp" > + + @@ -290,13 +294,17 @@ Name="Representation" > + + From c150e9945cde82859a98eba61114abdd5d83d92a Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 29 May 2009 22:36:52 +0000 Subject: [PATCH 095/295] Patch for gcc -Wall (order of initialization) --- src/alias.h | 68 +++++++++++++++++++++++++------------------------- src/stream.cpp | 2 +- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/alias.h b/src/alias.h index ad80b79..dfe00dd 100644 --- a/src/alias.h +++ b/src/alias.h @@ -1,35 +1,35 @@ -#pragma once - -#include "content.h" - -namespace YAML -{ - class Alias : public Content - { - public: - Alias(Content *pNodeContent); - - virtual void Parse(Scanner* pScanner, const ParserState& state); - virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); - - virtual bool GetBegin(std::vector ::const_iterator&) const; - virtual bool GetBegin(std::map ::const_iterator&) const; - virtual bool GetEnd(std::vector ::const_iterator&) const; - virtual bool GetEnd(std::map ::const_iterator&) const; - virtual Node* GetNode(unsigned) const; - virtual unsigned GetSize() const; - virtual bool IsScalar() const; - virtual bool IsMap() const; - virtual bool IsSequence() const; - +#pragma once + +#include "content.h" + +namespace YAML +{ + class Alias : public Content + { + public: + Alias(Content *pNodeContent); + + virtual void Parse(Scanner* pScanner, const ParserState& state); + virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); + + virtual bool GetBegin(std::vector ::const_iterator&) const; + virtual bool GetBegin(std::map ::const_iterator&) const; + virtual bool GetEnd(std::vector ::const_iterator&) const; + virtual bool GetEnd(std::map ::const_iterator&) const; + virtual Node* GetNode(unsigned) const; + virtual unsigned GetSize() const; + virtual bool IsScalar() const; + virtual bool IsMap() const; + virtual bool IsSequence() const; + virtual bool GetScalar(std::string& s) const; - - virtual int Compare(Content *); - virtual int Compare(Scalar *); - virtual int Compare(Sequence *); - virtual int Compare(Map *); - - private: - Content* m_pRef; - }; -} + + virtual int Compare(Content *); + virtual int Compare(Scalar *); + virtual int Compare(Sequence *); + virtual int Compare(Map *); + + private: + Content* m_pRef; + }; +} diff --git a/src/stream.cpp b/src/stream.cpp index 97da1d4..4ca4f96 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -4,7 +4,7 @@ namespace YAML { - Stream::Stream(std::istream& input): buffer(0), pos(0), line(0), column(0), size(0) + Stream::Stream(std::istream& input): pos(0), line(0), column(0), size(0), buffer(0) { if(!input) return; From b444913576f01fa001dc5cb77a5793885e526043 Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 29 May 2009 22:48:25 +0000 Subject: [PATCH 096/295] Patch to simplify CMakeLists.txt files --- CMakeLists.txt | 71 +++++--------------------------------- yaml-reader/CMakeLists.txt | 6 ++-- 2 files changed, 11 insertions(+), 66 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 287677d..2c7d226 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,73 +1,18 @@ cmake_minimum_required(VERSION 2.6) project (YAML_CPP) -set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) +set(LIBRARY_OUTPUT_PATH ${YAML_CPP_SOURCE_DIR}/lib) -set(PUB_HDR - include/conversion.h - include/crt.h - include/emitter.h - include/emittermanip.h - include/exceptions.h - include/iterator.h - include/node.h - include/noncopyable.h - include/ostream.h - include/parser.h - include/parserstate.h - include/stlemitter.h - include/yaml.h -) - -set(PVT_HDR - src/alias.h - src/content.h - src/emitterstate.h - src/emitterutils.h - src/exp.h - src/indentation.h - src/iterpriv.h - src/ltnode.h - src/map.h - src/regex.h - src/scalar.h - src/scanner.h - src/scanscalar.h - src/sequence.h - src/setting.h - src/stream.h - src/token.h -) - -set(SRC - src/alias.cpp - src/content.cpp - src/conversion.cpp - src/emitter.cpp - src/emitterstate.cpp - src/emitterutils.cpp - src/exp.cpp - src/iterator.cpp - src/map.cpp - src/node.cpp - src/ostream.cpp - src/parser.cpp - src/parserstate.cpp - src/regex.cpp - src/scalar.cpp - src/scanner.cpp - src/scanscalar.cpp - src/scantoken.cpp - src/sequence.cpp - src/simplekey.cpp - src/stream.cpp -) +file(GLOB public_headers include/*.h) +file(GLOB private_headers src/*.h) +file(GLOB sources src/*.cpp) include_directories(${YAML_CPP_SOURCE_DIR}/include) add_library(yaml-cpp - ${PUB_HDR} - ${PVT_HDR} - ${SRC} + ${public_headers} + ${private_headers} + ${sources} ) add_subdirectory (yaml-reader) + diff --git a/yaml-reader/CMakeLists.txt b/yaml-reader/CMakeLists.txt index 7e3f6b3..082a38a 100644 --- a/yaml-reader/CMakeLists.txt +++ b/yaml-reader/CMakeLists.txt @@ -1,6 +1,6 @@ -set(FILES main.cpp tests.cpp) +set(yaml-reader_sources main.cpp tests.cpp) include_directories(${YAML_CPP_SOURCE_DIR}/include) -link_directories(${YAML_CPP_BINARY_DIR}/bin) +link_directories(${YAML_CPP_SOURCE_DIR}/lib) -add_executable(yaml-reader ${FILES}) +add_executable(yaml-reader ${yaml-reader_sources}) target_link_libraries(yaml-reader yaml-cpp) From ade7e7cd180df434370d12f4596eaf4bbe5b45ba Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 29 May 2009 22:55:59 +0000 Subject: [PATCH 097/295] Patched - install target --- CMakeLists.txt | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c7d226..fb130a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,9 @@ cmake_minimum_required(VERSION 2.6) project (YAML_CPP) -set(LIBRARY_OUTPUT_PATH ${YAML_CPP_SOURCE_DIR}/lib) +set(LIBRARY_OUTPUT_PATH lib${LIB_SUFFIX}) +set(LIB_INSTALL_DIR lib${LIB_SUFFIX}) +set(INCLUDE_INSTALL_DIR include/yaml-cpp) file(GLOB public_headers include/*.h) file(GLOB private_headers src/*.h) @@ -14,5 +16,15 @@ add_library(yaml-cpp ${sources} ) +install( + TARGETS yaml-cpp + LIBRARY ARCHIVE + DESTINATION ${LIB_INSTALL_DIR} +) +install( + FILES ${public_headers} + DESTINATION ${INCLUDE_INSTALL_DIR} +) + add_subdirectory (yaml-reader) From 2fdf2475bbeb68d3c15731a25323604975be1c0f Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 29 May 2009 22:58:14 +0000 Subject: [PATCH 098/295] Patched - removed unnecessary CMake statements --- yaml-reader/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/yaml-reader/CMakeLists.txt b/yaml-reader/CMakeLists.txt index 082a38a..2cc85ef 100644 --- a/yaml-reader/CMakeLists.txt +++ b/yaml-reader/CMakeLists.txt @@ -1,6 +1,4 @@ set(yaml-reader_sources main.cpp tests.cpp) -include_directories(${YAML_CPP_SOURCE_DIR}/include) -link_directories(${YAML_CPP_SOURCE_DIR}/lib) add_executable(yaml-reader ${yaml-reader_sources}) target_link_libraries(yaml-reader yaml-cpp) From f09e4497b654af45db23d7ee2344b648bd440f94 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sat, 30 May 2009 02:29:47 +0000 Subject: [PATCH 099/295] Set eol-style to native on all of the new files --- include/conversion.h | 70 +++++++++--------- src/alias.h | 70 +++++++++--------- src/conversion.cpp | 172 +++++++++++++++++++++---------------------- 3 files changed, 156 insertions(+), 156 deletions(-) diff --git a/include/conversion.h b/include/conversion.h index 12f688c..208a1ef 100644 --- a/include/conversion.h +++ b/include/conversion.h @@ -1,35 +1,35 @@ -#pragma once - -#include -#include - -namespace YAML -{ - template - struct Converter { - static bool Convert(const std::string& input, T& output); - }; - - template - bool Convert(const std::string& input, T& output) { - return Converter::Convert(input, output); - } - - // this is the one to specialize - template - inline bool Converter::Convert(const std::string& input, T& output) { - std::stringstream stream(input); - stream >> output; - return !stream.fail(); - } - - // specializations - template <> - inline bool Converter::Convert(const std::string& input, std::string& output) { - output = input; - return true; - } - - template <> - bool Converter::Convert(const std::string& input, bool& output); -} +#pragma once + +#include +#include + +namespace YAML +{ + template + struct Converter { + static bool Convert(const std::string& input, T& output); + }; + + template + bool Convert(const std::string& input, T& output) { + return Converter::Convert(input, output); + } + + // this is the one to specialize + template + inline bool Converter::Convert(const std::string& input, T& output) { + std::stringstream stream(input); + stream >> output; + return !stream.fail(); + } + + // specializations + template <> + inline bool Converter::Convert(const std::string& input, std::string& output) { + output = input; + return true; + } + + template <> + bool Converter::Convert(const std::string& input, bool& output); +} diff --git a/src/alias.h b/src/alias.h index dfe00dd..9513665 100644 --- a/src/alias.h +++ b/src/alias.h @@ -1,35 +1,35 @@ -#pragma once - -#include "content.h" - -namespace YAML -{ - class Alias : public Content - { - public: - Alias(Content *pNodeContent); - - virtual void Parse(Scanner* pScanner, const ParserState& state); - virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); - - virtual bool GetBegin(std::vector ::const_iterator&) const; - virtual bool GetBegin(std::map ::const_iterator&) const; - virtual bool GetEnd(std::vector ::const_iterator&) const; - virtual bool GetEnd(std::map ::const_iterator&) const; - virtual Node* GetNode(unsigned) const; - virtual unsigned GetSize() const; - virtual bool IsScalar() const; - virtual bool IsMap() const; - virtual bool IsSequence() const; - - virtual bool GetScalar(std::string& s) const; - - virtual int Compare(Content *); - virtual int Compare(Scalar *); - virtual int Compare(Sequence *); - virtual int Compare(Map *); - - private: - Content* m_pRef; - }; -} +#pragma once + +#include "content.h" + +namespace YAML +{ + class Alias : public Content + { + public: + Alias(Content *pNodeContent); + + virtual void Parse(Scanner* pScanner, const ParserState& state); + virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); + + virtual bool GetBegin(std::vector ::const_iterator&) const; + virtual bool GetBegin(std::map ::const_iterator&) const; + virtual bool GetEnd(std::vector ::const_iterator&) const; + virtual bool GetEnd(std::map ::const_iterator&) const; + virtual Node* GetNode(unsigned) const; + virtual unsigned GetSize() const; + virtual bool IsScalar() const; + virtual bool IsMap() const; + virtual bool IsSequence() const; + + virtual bool GetScalar(std::string& s) const; + + virtual int Compare(Content *); + virtual int Compare(Scalar *); + virtual int Compare(Sequence *); + virtual int Compare(Map *); + + private: + Content* m_pRef; + }; +} diff --git a/src/conversion.cpp b/src/conversion.cpp index b990314..0b34501 100644 --- a/src/conversion.cpp +++ b/src/conversion.cpp @@ -1,86 +1,86 @@ -#include "conversion.h" -#include - - -//////////////////////////////////////////////////////////////// -// Specializations for converting a string to specific types - -namespace -{ - // we're not gonna mess with the mess that is all the isupper/etc. functions - bool IsLower(char ch) { return 'a' <= ch && ch <= 'z'; } - bool IsUpper(char ch) { return 'A' <= ch && ch <= 'Z'; } - char ToLower(char ch) { return IsUpper(ch) ? ch + 'a' - 'A' : ch; } - - std::string tolower(const std::string& str) - { - std::string s(str); - std::transform(s.begin(), s.end(), s.begin(), ToLower); - return s; - } - - template - bool IsEntirely(const std::string& str, T func) - { - for(unsigned i=0;i - bool Converter::Convert(const std::string& input, bool& b) - { - // we can't use iostream bool extraction operators as they don't - // recognize all possible values in the table below (taken from - // http://yaml.org/type/bool.html) - static const struct { - std::string truename, falsename; - } names[] = { - { "y", "n" }, - { "yes", "no" }, - { "true", "false" }, - { "on", "off" }, - }; - - if(!IsFlexibleCase(input)) - return false; - - for(unsigned i=0;i + + +//////////////////////////////////////////////////////////////// +// Specializations for converting a string to specific types + +namespace +{ + // we're not gonna mess with the mess that is all the isupper/etc. functions + bool IsLower(char ch) { return 'a' <= ch && ch <= 'z'; } + bool IsUpper(char ch) { return 'A' <= ch && ch <= 'Z'; } + char ToLower(char ch) { return IsUpper(ch) ? ch + 'a' - 'A' : ch; } + + std::string tolower(const std::string& str) + { + std::string s(str); + std::transform(s.begin(), s.end(), s.begin(), ToLower); + return s; + } + + template + bool IsEntirely(const std::string& str, T func) + { + for(unsigned i=0;i + bool Converter::Convert(const std::string& input, bool& b) + { + // we can't use iostream bool extraction operators as they don't + // recognize all possible values in the table below (taken from + // http://yaml.org/type/bool.html) + static const struct { + std::string truename, falsename; + } names[] = { + { "y", "n" }, + { "yes", "no" }, + { "true", "false" }, + { "on", "off" }, + }; + + if(!IsFlexibleCase(input)) + return false; + + for(unsigned i=0;i Date: Sat, 30 May 2009 02:41:27 +0000 Subject: [PATCH 100/295] Patch - added testing --- CMakeLists.txt | 3 +++ yaml-reader/CMakeLists.txt | 2 ++ 2 files changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index fb130a3..1d75d3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,9 @@ cmake_minimum_required(VERSION 2.6) project (YAML_CPP) + +enable_testing() + set(LIBRARY_OUTPUT_PATH lib${LIB_SUFFIX}) set(LIB_INSTALL_DIR lib${LIB_SUFFIX}) set(INCLUDE_INSTALL_DIR include/yaml-cpp) diff --git a/yaml-reader/CMakeLists.txt b/yaml-reader/CMakeLists.txt index 2cc85ef..866bfe0 100644 --- a/yaml-reader/CMakeLists.txt +++ b/yaml-reader/CMakeLists.txt @@ -2,3 +2,5 @@ set(yaml-reader_sources main.cpp tests.cpp) add_executable(yaml-reader ${yaml-reader_sources}) target_link_libraries(yaml-reader yaml-cpp) + +add_test(yaml-reader-test yaml-reader) From ec578d45f1c1f71da3fcfbbfd07c4c949092fe1a Mon Sep 17 00:00:00 2001 From: jbeder Date: Sun, 31 May 2009 06:36:01 +0000 Subject: [PATCH 101/295] Switched from loading test files to testing specific parsing constructs. The tests don't fully cover the span (eventually I'll add more, maybe), but there's a bunch there. More to the point, the yaml-reader program doesn't do any file IO, so it doesn't require a specific working directory. --- yaml-reader.vcproj | 34 +- yaml-reader/emittertests.cpp | 514 +++++++++++++++++++++ yaml-reader/main.cpp | 29 +- yaml-reader/parsertests.cpp | 222 +++++++++ yaml-reader/tests.cpp | 742 +++++------------------------- yaml-reader/tests.h | 26 +- yaml-reader/tests/directives.yaml | 5 - yaml-reader/tests/mixed.yaml | 32 -- yaml-reader/tests/scalars.yaml | 35 -- yaml-reader/tests/simple.yaml | 13 - yaml-reader/tests/test.yaml | 4 - 11 files changed, 890 insertions(+), 766 deletions(-) create mode 100644 yaml-reader/emittertests.cpp create mode 100644 yaml-reader/parsertests.cpp delete mode 100644 yaml-reader/tests/directives.yaml delete mode 100644 yaml-reader/tests/mixed.yaml delete mode 100644 yaml-reader/tests/scalars.yaml delete mode 100644 yaml-reader/tests/simple.yaml delete mode 100644 yaml-reader/tests/test.yaml diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index 57d70b9..84ad1d3 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -167,10 +167,18 @@ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > + + + + @@ -186,32 +194,6 @@ > - - - - - - - - - - - - diff --git a/yaml-reader/emittertests.cpp b/yaml-reader/emittertests.cpp new file mode 100644 index 0000000..8836c58 --- /dev/null +++ b/yaml-reader/emittertests.cpp @@ -0,0 +1,514 @@ +#include "tests.h" +#include "yaml.h" + +namespace Test +{ + namespace Emitter { + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // correct emitting + + void SimpleScalar(YAML::Emitter& out, std::string& desiredOutput) { + out << "Hello, World!"; + desiredOutput = "Hello, World!"; + } + + void SimpleSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginSeq; + out << "eggs"; + out << "bread"; + out << "milk"; + out << YAML::EndSeq; + + desiredOutput = "- eggs\n- bread\n- milk"; + } + + void SimpleFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::Flow; + out << YAML::BeginSeq; + out << "Larry"; + out << "Curly"; + out << "Moe"; + out << YAML::EndSeq; + + desiredOutput = "[Larry, Curly, Moe]"; + } + + void EmptyFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::Flow; + out << YAML::BeginSeq; + out << YAML::EndSeq; + + desiredOutput = "[]"; + } + + void NestedBlockSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginSeq; + out << "item 1"; + out << YAML::BeginSeq << "subitem 1" << "subitem 2" << YAML::EndSeq; + out << YAML::EndSeq; + + desiredOutput = "- item 1\n-\n - subitem 1\n - subitem 2"; + } + + void NestedFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginSeq; + out << "one"; + out << YAML::Flow << YAML::BeginSeq << "two" << "three" << YAML::EndSeq; + out << YAML::EndSeq; + + desiredOutput = "- one\n- [two, three]"; + } + + void SimpleMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Ryan Braun"; + out << YAML::Key << "position"; + out << YAML::Value << "3B"; + out << YAML::EndMap; + + desiredOutput = "name: Ryan Braun\nposition: 3B"; + } + + void SimpleFlowMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::Flow; + out << YAML::BeginMap; + out << YAML::Key << "shape"; + out << YAML::Value << "square"; + out << YAML::Key << "color"; + out << YAML::Value << "blue"; + out << YAML::EndMap; + + desiredOutput = "{shape: square, color: blue}"; + } + + void MapAndList(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Barack Obama"; + out << YAML::Key << "children"; + out << YAML::Value << YAML::BeginSeq << "Sasha" << "Malia" << YAML::EndSeq; + out << YAML::EndMap; + + desiredOutput = "name: Barack Obama\nchildren:\n - Sasha\n - Malia"; + } + + void ListAndMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginSeq; + out << "item 1"; + out << YAML::BeginMap; + out << YAML::Key << "pens" << YAML::Value << 8; + out << YAML::Key << "pencils" << YAML::Value << 14; + out << YAML::EndMap; + out << "item 2"; + out << YAML::EndSeq; + + desiredOutput = "- item 1\n-\n pens: 8\n pencils: 14\n- item 2"; + } + + void NestedBlockMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Fred"; + out << YAML::Key << "grades"; + out << YAML::Value; + out << YAML::BeginMap; + out << YAML::Key << "algebra" << YAML::Value << "A"; + out << YAML::Key << "physics" << YAML::Value << "C+"; + out << YAML::Key << "literature" << YAML::Value << "B"; + out << YAML::EndMap; + out << YAML::EndMap; + + desiredOutput = "name: Fred\ngrades:\n algebra: A\n physics: C+\n literature: B"; + } + + void NestedFlowMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::Flow; + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Fred"; + out << YAML::Key << "grades"; + out << YAML::Value; + out << YAML::BeginMap; + out << YAML::Key << "algebra" << YAML::Value << "A"; + out << YAML::Key << "physics" << YAML::Value << "C+"; + out << YAML::Key << "literature" << YAML::Value << "B"; + out << YAML::EndMap; + out << YAML::EndMap; + + desiredOutput = "{name: Fred, grades: {algebra: A, physics: C+, literature: B}}"; + } + + void MapListMix(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Bob"; + out << YAML::Key << "position"; + out << YAML::Value; + out << YAML::Flow << YAML::BeginSeq << 2 << 4 << YAML::EndSeq; + out << YAML::Key << "invincible" << YAML::Value << YAML::OnOffBool << false; + out << YAML::EndMap; + + desiredOutput = "name: Bob\nposition: [2, 4]\ninvincible: off"; + } + + void SimpleLongKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::LongKey; + out << YAML::BeginMap; + out << YAML::Key << "height"; + out << YAML::Value << "5'9\""; + out << YAML::Key << "weight"; + out << YAML::Value << 145; + out << YAML::EndMap; + + desiredOutput = "? height\n: 5'9\"\n? weight\n: 145"; + } + + void SingleLongKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << "age"; + out << YAML::Value << "24"; + out << YAML::LongKey << YAML::Key << "height"; + out << YAML::Value << "5'9\""; + out << YAML::Key << "weight"; + out << YAML::Value << 145; + out << YAML::EndMap; + + desiredOutput = "age: 24\n? height\n: 5'9\"\nweight: 145"; + } + + void ComplexLongKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::LongKey; + out << YAML::BeginMap; + out << YAML::Key << YAML::BeginSeq << 1 << 3 << YAML::EndSeq; + out << YAML::Value << "monster"; + out << YAML::Key << YAML::Flow << YAML::BeginSeq << 2 << 0 << YAML::EndSeq; + out << YAML::Value << "demon"; + out << YAML::EndMap; + + desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon"; + } + + void AutoLongKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << YAML::BeginSeq << 1 << 3 << YAML::EndSeq; + out << YAML::Value << "monster"; + out << YAML::Key << YAML::Flow << YAML::BeginSeq << 2 << 0 << YAML::EndSeq; + out << YAML::Value << "demon"; + out << YAML::Key << "the origin"; + out << YAML::Value << "angel"; + out << YAML::EndMap; + + desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon\nthe origin: angel"; + } + + void ScalarFormat(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << "simple scalar"; + out << YAML::SingleQuoted << "explicit single-quoted scalar"; + out << YAML::DoubleQuoted << "explicit double-quoted scalar"; + out << "auto-detected\ndouble-quoted scalar"; + out << "a non-\"auto-detected\" double-quoted scalar"; + out << YAML::Literal << "literal scalar\nthat may span\nmany, many\nlines and have \"whatever\" crazy\tsymbols that we like"; + out << YAML::EndSeq; + + desiredOutput = "- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\xadouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like"; + } + + void AutoLongKeyScalar(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << YAML::Literal << "multi-line\nscalar"; + out << YAML::Value << "and its value"; + out << YAML::EndMap; + + desiredOutput = "? |\n multi-line\n scalar\n: and its value"; + } + + void LongKeyFlowMap(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Flow; + out << YAML::BeginMap; + out << YAML::Key << "simple key"; + out << YAML::Value << "and value"; + out << YAML::LongKey << YAML::Key << "long key"; + out << YAML::Value << "and its value"; + out << YAML::EndMap; + + desiredOutput = "{simple key: and value, ? long key: and its value}"; + } + + void BlockMapAsKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key; + out << YAML::BeginMap; + out << YAML::Key << "key" << YAML::Value << "value"; + out << YAML::Key << "next key" << YAML::Value << "next value"; + out << YAML::EndMap; + out << YAML::Value; + out << "total value"; + out << YAML::EndMap; + + desiredOutput = "?\n key: value\n next key: next value\n: total value"; + } + + void AliasAndAnchor(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << YAML::Anchor("fred"); + out << YAML::BeginMap; + out << YAML::Key << "name" << YAML::Value << "Fred"; + out << YAML::Key << "age" << YAML::Value << 42; + out << YAML::EndMap; + out << YAML::Alias("fred"); + out << YAML::EndSeq; + + desiredOutput = "- &fred\n name: Fred\n age: 42\n- *fred"; + } + + void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << "receipt"; + out << YAML::Value << "Oz-Ware Purchase Invoice"; + out << YAML::Key << "date"; + out << YAML::Value << "2007-08-06"; + out << YAML::Key << "customer"; + out << YAML::Value; + out << YAML::BeginMap; + out << YAML::Key << "given"; + out << YAML::Value << "Dorothy"; + out << YAML::Key << "family"; + out << YAML::Value << "Gale"; + out << YAML::EndMap; + out << YAML::Key << "items"; + out << YAML::Value; + out << YAML::BeginSeq; + out << YAML::BeginMap; + out << YAML::Key << "part_no"; + out << YAML::Value << "A4786"; + out << YAML::Key << "descrip"; + out << YAML::Value << "Water Bucket (Filled)"; + out << YAML::Key << "price"; + out << YAML::Value << 1.47; + out << YAML::Key << "quantity"; + out << YAML::Value << 4; + out << YAML::EndMap; + out << YAML::BeginMap; + out << YAML::Key << "part_no"; + out << YAML::Value << "E1628"; + out << YAML::Key << "descrip"; + out << YAML::Value << "High Heeled \"Ruby\" Slippers"; + out << YAML::Key << "price"; + out << YAML::Value << 100.27; + out << YAML::Key << "quantity"; + out << YAML::Value << 1; + out << YAML::EndMap; + out << YAML::EndSeq; + out << YAML::Key << "bill-to"; + out << YAML::Value << YAML::Anchor("id001"); + out << YAML::BeginMap; + out << YAML::Key << "street"; + out << YAML::Value << YAML::Literal << "123 Tornado Alley\nSuite 16"; + out << YAML::Key << "city"; + out << YAML::Value << "East Westville"; + out << YAML::Key << "state"; + out << YAML::Value << "KS"; + out << YAML::EndMap; + out << YAML::Key << "ship-to"; + out << YAML::Value << YAML::Alias("id001"); + out << YAML::EndMap; + + desiredOutput = "receipt: Oz-Ware Purchase Invoice\ndate: 2007-08-06\ncustomer:\n given: Dorothy\n family: Gale\nitems:\n -\n part_no: A4786\n descrip: Water Bucket (Filled)\n price: 1.47\n quantity: 4\n -\n part_no: E1628\n descrip: High Heeled \"Ruby\" Slippers\n price: 100.27\n quantity: 1\nbill-to: &id001\n street: |\n 123 Tornado Alley\n Suite 16\n city: East Westville\n state: KS\nship-to: *id001"; + } + + void STLContainers(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + std::vector primes; + primes.push_back(2); + primes.push_back(3); + primes.push_back(5); + primes.push_back(7); + primes.push_back(11); + primes.push_back(13); + out << YAML::Flow << primes; + std::map ages; + ages["Daniel"] = 26; + ages["Jesse"] = 24; + out << ages; + out << YAML::EndSeq; + + desiredOutput = "- [2, 3, 5, 7, 11, 13]\n-\n Daniel: 26\n Jesse: 24"; + } + + void SimpleComment(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << "method"; + out << YAML::Value << "least squares" << YAML::Comment("should we change this method?"); + out << YAML::EndMap; + + desiredOutput = "method: least squares # should we change this method?"; + } + + void MultiLineComment(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << "item 1" << YAML::Comment("really really long\ncomment that couldn't possibly\nfit on one line"); + out << "item 2"; + out << YAML::EndSeq; + + desiredOutput = "- item 1 # really really long\n # comment that couldn't possibly\n # fit on one line\n- item 2"; + } + + void ComplexComments(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::LongKey << YAML::Key << "long key" << YAML::Comment("long key"); + out << YAML::Value << "value"; + out << YAML::EndMap; + + desiredOutput = "? long key # long key\n: value"; + } + + void Indentation(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Indent(4); + out << YAML::BeginSeq; + out << YAML::BeginMap; + out << YAML::Key << "key 1" << YAML::Value << "value 1"; + out << YAML::Key << "key 2" << YAML::Value << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; + out << YAML::EndMap; + out << YAML::EndSeq; + + desiredOutput = "-\n key 1: value 1\n key 2:\n - a\n - b\n - c"; + } + + void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) + { + out.SetIndent(4); + out.SetMapFormat(YAML::LongKey); + + out << YAML::BeginSeq; + out << YAML::BeginMap; + out << YAML::Key << "key 1" << YAML::Value << "value 1"; + out << YAML::Key << "key 2" << YAML::Value << YAML::Flow << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; + out << YAML::EndMap; + out << YAML::EndSeq; + + desiredOutput = "-\n ? key 1\n : value 1\n ? key 2\n : [a, b, c]"; + } + + void ComplexGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << YAML::Block; + out << YAML::BeginMap; + out << YAML::Key << "key 1" << YAML::Value << "value 1"; + out << YAML::Key << "key 2" << YAML::Value; + out.SetSeqFormat(YAML::Flow); + out << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; + out << YAML::EndMap; + out << YAML::BeginMap; + out << YAML::Key << YAML::BeginSeq << 1 << 2 << YAML::EndSeq; + out << YAML::Value << YAML::BeginMap << YAML::Key << "a" << YAML::Value << "b" << YAML::EndMap; + out << YAML::EndMap; + out << YAML::EndSeq; + + desiredOutput = "-\n key 1: value 1\n key 2: [a, b, c]\n-\n ? [1, 2]\n :\n a: b"; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // incorrect emitting + + void ExtraEndSeq(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::UNEXPECTED_END_SEQ; + + out << YAML::BeginSeq; + out << "Hello"; + out << "World"; + out << YAML::EndSeq; + out << YAML::EndSeq; + } + + void ExtraEndMap(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::UNEXPECTED_END_MAP; + + out << YAML::BeginMap; + out << YAML::Key << "Hello" << YAML::Value << "World"; + out << YAML::EndMap; + out << YAML::EndMap; + } + + void BadSingleQuoted(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::SINGLE_QUOTED_CHAR; + + out << YAML::SingleQuoted << "Hello\nWorld"; + } + + void InvalidAnchor(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::INVALID_ANCHOR; + + out << YAML::BeginSeq; + out << YAML::Anchor("new\nline") << "Test"; + out << YAML::EndSeq; + } + + void InvalidAlias(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::INVALID_ALIAS; + + out << YAML::BeginSeq; + out << YAML::Alias("new\nline"); + out << YAML::EndSeq; + } + + void MissingKey(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::EXPECTED_KEY_TOKEN; + + out << YAML::BeginMap; + out << YAML::Key << "key" << YAML::Value << "value"; + out << "missing key" << YAML::Value << "value"; + out << YAML::EndMap; + } + + void MissingValue(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::EXPECTED_VALUE_TOKEN; + + out << YAML::BeginMap; + out << YAML::Key << "key" << "value"; + out << YAML::EndMap; + } + + void UnexpectedKey(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::UNEXPECTED_KEY_TOKEN; + + out << YAML::BeginSeq; + out << YAML::Key << "hi"; + out << YAML::EndSeq; + } + + void UnexpectedValue(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::UNEXPECTED_VALUE_TOKEN; + + out << YAML::BeginSeq; + out << YAML::Value << "hi"; + out << YAML::EndSeq; + } + } +} diff --git a/yaml-reader/main.cpp b/yaml-reader/main.cpp index 7cf8a26..d047b3f 100644 --- a/yaml-reader/main.cpp +++ b/yaml-reader/main.cpp @@ -1,38 +1,11 @@ -#include "yaml.h" #include "tests.h" -#include -#include -#include - -void run() -{ - std::ifstream fin("tests/test.yaml"); - YAML::Parser parser(fin); - - while(parser) - { - YAML::Node doc; - parser.GetNextDocument(doc); - std::cout << doc; - } - - // try some output - YAML::Emitter out; -} int main(int argc, char **argv) { - bool verbose = false; - for(int i=1;i + +namespace Test +{ + namespace Parser { + void SimpleScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = "Hello, World!"; + desiredOutput = "Hello, World!"; + } + + void MultiLineScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = + "normal scalar, but\n" + "over several lines"; + desiredOutput = "normal scalar, but over several lines"; + } + + void LiteralScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = + "|\n" + " literal scalar - so we can draw ASCII:\n" + " \n" + " - -\n" + " | - |\n" + " -----\n"; + desiredOutput = + "literal scalar - so we can draw ASCII:\n" + "\n" + " - -\n" + " | - |\n" + " -----\n"; + } + + void FoldedScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = + ">\n" + " and a folded scalar... so we\n" + " can just keep writing various\n" + " things. And if we want to keep indentation:\n" + " \n" + " we just indent a little\n" + " see, this stays indented"; + desiredOutput = + "and a folded scalar... so we" + " can just keep writing various" + " things. And if we want to keep indentation:\n" + "\n" + " we just indent a little\n" + " see, this stays indented"; + } + + void ChompedFoldedScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = + ">-\n" + " Here's a folded scalar\n" + " that gets chomped."; + desiredOutput = + "Here's a folded scalar" + " that gets chomped."; + } + + void ChompedLiteralScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = + "|-\n" + " Here's a literal scalar\n" + " that gets chomped."; + desiredOutput = + "Here's a literal scalar\n" + "that gets chomped."; + } + + void FoldedScalarWithIndent(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = + ">2\n" + " Here's a folded scalar\n" + " that starts with some indentation."; + desiredOutput = + " Here's a folded scalar\n" + "that starts with some indentation."; + } + + void ColonScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = "::vector"; + desiredOutput = "::vector"; + } + + void QuotedScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = "\": - ()\""; + desiredOutput = ": - ()"; + } + + void CommaScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = "Up, up, and away!"; + desiredOutput = "Up, up, and away!"; + } + + void DashScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = "-123"; + desiredOutput = "-123"; + } + + void URLScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = "http://example.com/foo#bar"; + desiredOutput = "http://example.com/foo#bar"; + } + + bool SimpleSeq() + { + std::string input = + "- eggs\n" + "- bread\n" + "- milk"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc[0] >> output; + if(output != "eggs") + return false; + doc[1] >> output; + if(output != "bread") + return false; + doc[2] >> output; + if(output != "milk") + return false; + + return true; + } + + bool SimpleMap() + { + std::string input = + "name: Prince Fielder\n" + "position: 1B\n" + "bats: L"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc["name"] >> output; + if(output != "Prince Fielder") + return false; + doc["position"] >> output; + if(output != "1B") + return false; + doc["bats"] >> output; + if(output != "L") + return false; + + return true; + } + + bool FlowSeq() + { + std::string input = "[ 2 , 3, 5 , 7, 11]"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + int output; + doc[0] >> output; + if(output != 2) + return false; + doc[1] >> output; + if(output != 3) + return false; + doc[2] >> output; + if(output != 5) + return false; + doc[3] >> output; + if(output != 7) + return false; + doc[4] >> output; + if(output != 11) + return false; + + return true; + } + + bool FlowMap() + { + std::string input = "{hr: 65, avg: 0.278}"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc["hr"] >> output; + if(output != "65") + return false; + doc["avg"] >> output; + if(output != "0.278") + return false; + + return true; + } + } +} diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp index 3bcb6b9..74a2dd2 100644 --- a/yaml-reader/tests.cpp +++ b/yaml-reader/tests.cpp @@ -7,24 +7,11 @@ namespace Test { - // runs all the tests on all data we have - void RunAll(bool verbose) + void RunAll() { - std::vector files; - files.push_back("tests/simple.yaml"); - files.push_back("tests/mixed.yaml"); - files.push_back("tests/scalars.yaml"); - files.push_back("tests/directives.yaml"); - files.push_back("tests/aliased.yaml"); - bool passed = true; - for(unsigned i=0;i> output; + } catch(const YAML::Exception& e) { + ok = false; + error = e.msg; + } + if(ok && output == desiredOutput) { + std::cout << "Parser test passed: " << name << "\n"; + } else { + passed = false; + std::cout << "Parser test failed: " << name << "\n"; + if(error != "") + std::cout << "Caught exception: " << error << "\n"; + else { + std::cout << "Output:\n" << output << "<<<\n"; + std::cout << "Desired output:\n" << desiredOutput << "<<<\n"; + } } - - return false; } - return true; + void RunParserTest(bool (*test)(), const std::string& name, bool& passed) { + std::string error; + bool ok = true; + try { + ok = test(); + } catch(const YAML::Exception& e) { + ok = false; + error = e.msg; + } + if(ok) { + std::cout << "Parser test passed: " << name << "\n"; + } else { + passed = false; + std::cout << "Parser test failed: " << name << "\n"; + if(error != "") + std::cout << "Caught exception: " << error << "\n"; + } + } } - + + bool RunParserTests() + { + bool passed = true; + RunScalarParserTest(&Parser::SimpleScalar, "simple scalar", passed); + RunScalarParserTest(&Parser::MultiLineScalar, "multi-line scalar", passed); + RunScalarParserTest(&Parser::LiteralScalar, "literal scalar", passed); + RunScalarParserTest(&Parser::FoldedScalar, "folded scalar", passed); + RunScalarParserTest(&Parser::ChompedFoldedScalar, "chomped folded scalar", passed); + RunScalarParserTest(&Parser::ChompedLiteralScalar, "chomped literal scalar", passed); + RunScalarParserTest(&Parser::FoldedScalarWithIndent, "folded scalar with indent", passed); + RunScalarParserTest(&Parser::ColonScalar, "colon scalar", passed); + RunScalarParserTest(&Parser::QuotedScalar, "quoted scalar", passed); + RunScalarParserTest(&Parser::CommaScalar, "comma scalar", passed); + RunScalarParserTest(&Parser::DashScalar, "dash scalar", passed); + RunScalarParserTest(&Parser::URLScalar, "url scalar", passed); + + RunParserTest(&Parser::SimpleSeq, "simple seq", passed); + RunParserTest(&Parser::SimpleMap, "simple map", passed); + RunParserTest(&Parser::FlowSeq, "flow seq", passed); + RunParserTest(&Parser::FlowMap, "flow map", passed); + return passed; + } + //////////////////////////////////////////////////////////////////////////////////////// // Emitter tests namespace { - void RunTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, bool& passed) { + void RunEmitterTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, bool& passed) { YAML::Emitter out; std::string desiredOutput; test(out, desiredOutput); std::string output = out.c_str(); if(output == desiredOutput) { - std::cout << "Test passed: " << name << "\n"; + std::cout << "Emitter test passed: " << name << "\n"; } else { passed = false; - std::cout << "Test failed: " << name << "\n"; + std::cout << "Emitter test failed: " << name << "\n"; std::cout << "Output:\n"; std::cout << output << "<<<\n"; std::cout << "Desired output:\n"; @@ -111,16 +119,16 @@ namespace Test } } - void RunErrorTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, bool& passed) { + void RunEmitterErrorTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, bool& passed) { YAML::Emitter out; std::string desiredError; test(out, desiredError); std::string lastError = out.GetLastError(); if(!out.good() && lastError == desiredError) { - std::cout << "Test passed: " << name << "\n"; + std::cout << "Emitter test passed: " << name << "\n"; } else { passed = false; - std::cout << "Test failed: " << name << "\n"; + std::cout << "Emitter test failed: " << name << "\n"; if(out.good()) std::cout << "No error detected\n"; else @@ -133,555 +141,47 @@ namespace Test bool RunEmitterTests() { bool passed = true; - RunTest(&Emitter::SimpleScalar, "simple scalar", passed); - RunTest(&Emitter::SimpleSeq, "simple seq", passed); - RunTest(&Emitter::SimpleFlowSeq, "simple flow seq", passed); - RunTest(&Emitter::EmptyFlowSeq, "empty flow seq", passed); - RunTest(&Emitter::NestedBlockSeq, "nested block seq", passed); - RunTest(&Emitter::NestedFlowSeq, "nested flow seq", passed); - RunTest(&Emitter::SimpleMap, "simple map", passed); - RunTest(&Emitter::SimpleFlowMap, "simple flow map", passed); - RunTest(&Emitter::MapAndList, "map and list", passed); - RunTest(&Emitter::ListAndMap, "list and map", passed); - RunTest(&Emitter::NestedBlockMap, "nested block map", passed); - RunTest(&Emitter::NestedFlowMap, "nested flow map", passed); - RunTest(&Emitter::MapListMix, "map list mix", passed); - RunTest(&Emitter::SimpleLongKey, "simple long key", passed); - RunTest(&Emitter::SingleLongKey, "single long key", passed); - RunTest(&Emitter::ComplexLongKey, "complex long key", passed); - RunTest(&Emitter::AutoLongKey, "auto long key", passed); - RunTest(&Emitter::ScalarFormat, "scalar format", passed); - RunTest(&Emitter::AutoLongKeyScalar, "auto long key scalar", passed); - RunTest(&Emitter::LongKeyFlowMap, "long key flow map", passed); - RunTest(&Emitter::BlockMapAsKey, "block map as key", passed); - RunTest(&Emitter::AliasAndAnchor, "alias and anchor", passed); - RunTest(&Emitter::ComplexDoc, "complex doc", passed); - RunTest(&Emitter::STLContainers, "STL containers", passed); - RunTest(&Emitter::SimpleComment, "simple comment", passed); - RunTest(&Emitter::MultiLineComment, "multi-line comment", passed); - RunTest(&Emitter::ComplexComments, "complex comments", passed); - RunTest(&Emitter::Indentation, "indentation", passed); - RunTest(&Emitter::SimpleGlobalSettings, "simple global settings", passed); - RunTest(&Emitter::ComplexGlobalSettings, "complex global settings", passed); + RunEmitterTest(&Emitter::SimpleScalar, "simple scalar", passed); + RunEmitterTest(&Emitter::SimpleSeq, "simple seq", passed); + RunEmitterTest(&Emitter::SimpleFlowSeq, "simple flow seq", passed); + RunEmitterTest(&Emitter::EmptyFlowSeq, "empty flow seq", passed); + RunEmitterTest(&Emitter::NestedBlockSeq, "nested block seq", passed); + RunEmitterTest(&Emitter::NestedFlowSeq, "nested flow seq", passed); + RunEmitterTest(&Emitter::SimpleMap, "simple map", passed); + RunEmitterTest(&Emitter::SimpleFlowMap, "simple flow map", passed); + RunEmitterTest(&Emitter::MapAndList, "map and list", passed); + RunEmitterTest(&Emitter::ListAndMap, "list and map", passed); + RunEmitterTest(&Emitter::NestedBlockMap, "nested block map", passed); + RunEmitterTest(&Emitter::NestedFlowMap, "nested flow map", passed); + RunEmitterTest(&Emitter::MapListMix, "map list mix", passed); + RunEmitterTest(&Emitter::SimpleLongKey, "simple long key", passed); + RunEmitterTest(&Emitter::SingleLongKey, "single long key", passed); + RunEmitterTest(&Emitter::ComplexLongKey, "complex long key", passed); + RunEmitterTest(&Emitter::AutoLongKey, "auto long key", passed); + RunEmitterTest(&Emitter::ScalarFormat, "scalar format", passed); + RunEmitterTest(&Emitter::AutoLongKeyScalar, "auto long key scalar", passed); + RunEmitterTest(&Emitter::LongKeyFlowMap, "long key flow map", passed); + RunEmitterTest(&Emitter::BlockMapAsKey, "block map as key", passed); + RunEmitterTest(&Emitter::AliasAndAnchor, "alias and anchor", passed); + RunEmitterTest(&Emitter::ComplexDoc, "complex doc", passed); + RunEmitterTest(&Emitter::STLContainers, "STL containers", passed); + RunEmitterTest(&Emitter::SimpleComment, "simple comment", passed); + RunEmitterTest(&Emitter::MultiLineComment, "multi-line comment", passed); + RunEmitterTest(&Emitter::ComplexComments, "complex comments", passed); + RunEmitterTest(&Emitter::Indentation, "indentation", passed); + RunEmitterTest(&Emitter::SimpleGlobalSettings, "simple global settings", passed); + RunEmitterTest(&Emitter::ComplexGlobalSettings, "complex global settings", passed); - RunErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed); - RunErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed); - RunErrorTest(&Emitter::BadSingleQuoted, "bad single quoted string", passed); - RunErrorTest(&Emitter::InvalidAnchor, "invalid anchor", passed); - RunErrorTest(&Emitter::InvalidAlias, "invalid alias", passed); - RunErrorTest(&Emitter::MissingKey, "missing key", passed); - RunErrorTest(&Emitter::MissingValue, "missing value", passed); - RunErrorTest(&Emitter::UnexpectedKey, "unexpected key", passed); - RunErrorTest(&Emitter::UnexpectedValue, "unexpected value", passed); + RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed); + RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed); + RunEmitterErrorTest(&Emitter::BadSingleQuoted, "bad single quoted string", passed); + RunEmitterErrorTest(&Emitter::InvalidAnchor, "invalid anchor", passed); + RunEmitterErrorTest(&Emitter::InvalidAlias, "invalid alias", passed); + RunEmitterErrorTest(&Emitter::MissingKey, "missing key", passed); + RunEmitterErrorTest(&Emitter::MissingValue, "missing value", passed); + RunEmitterErrorTest(&Emitter::UnexpectedKey, "unexpected key", passed); + RunEmitterErrorTest(&Emitter::UnexpectedValue, "unexpected value", passed); return passed; } - namespace Emitter { - //////////////////////////////////////////////////////////////////////////////////////////////////////// - // correct emitting - - void SimpleScalar(YAML::Emitter& out, std::string& desiredOutput) { - out << "Hello, World!"; - desiredOutput = "Hello, World!"; - } - - void SimpleSeq(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginSeq; - out << "eggs"; - out << "bread"; - out << "milk"; - out << YAML::EndSeq; - - desiredOutput = "- eggs\n- bread\n- milk"; - } - - void SimpleFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::Flow; - out << YAML::BeginSeq; - out << "Larry"; - out << "Curly"; - out << "Moe"; - out << YAML::EndSeq; - - desiredOutput = "[Larry, Curly, Moe]"; - } - - void EmptyFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::Flow; - out << YAML::BeginSeq; - out << YAML::EndSeq; - - desiredOutput = "[]"; - } - - void NestedBlockSeq(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginSeq; - out << "item 1"; - out << YAML::BeginSeq << "subitem 1" << "subitem 2" << YAML::EndSeq; - out << YAML::EndSeq; - - desiredOutput = "- item 1\n-\n - subitem 1\n - subitem 2"; - } - - void NestedFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginSeq; - out << "one"; - out << YAML::Flow << YAML::BeginSeq << "two" << "three" << YAML::EndSeq; - out << YAML::EndSeq; - - desiredOutput = "- one\n- [two, three]"; - } - - void SimpleMap(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginMap; - out << YAML::Key << "name"; - out << YAML::Value << "Ryan Braun"; - out << YAML::Key << "position"; - out << YAML::Value << "3B"; - out << YAML::EndMap; - - desiredOutput = "name: Ryan Braun\nposition: 3B"; - } - - void SimpleFlowMap(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::Flow; - out << YAML::BeginMap; - out << YAML::Key << "shape"; - out << YAML::Value << "square"; - out << YAML::Key << "color"; - out << YAML::Value << "blue"; - out << YAML::EndMap; - - desiredOutput = "{shape: square, color: blue}"; - } - - void MapAndList(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginMap; - out << YAML::Key << "name"; - out << YAML::Value << "Barack Obama"; - out << YAML::Key << "children"; - out << YAML::Value << YAML::BeginSeq << "Sasha" << "Malia" << YAML::EndSeq; - out << YAML::EndMap; - - desiredOutput = "name: Barack Obama\nchildren:\n - Sasha\n - Malia"; - } - - void ListAndMap(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginSeq; - out << "item 1"; - out << YAML::BeginMap; - out << YAML::Key << "pens" << YAML::Value << 8; - out << YAML::Key << "pencils" << YAML::Value << 14; - out << YAML::EndMap; - out << "item 2"; - out << YAML::EndSeq; - - desiredOutput = "- item 1\n-\n pens: 8\n pencils: 14\n- item 2"; - } - - void NestedBlockMap(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginMap; - out << YAML::Key << "name"; - out << YAML::Value << "Fred"; - out << YAML::Key << "grades"; - out << YAML::Value; - out << YAML::BeginMap; - out << YAML::Key << "algebra" << YAML::Value << "A"; - out << YAML::Key << "physics" << YAML::Value << "C+"; - out << YAML::Key << "literature" << YAML::Value << "B"; - out << YAML::EndMap; - out << YAML::EndMap; - - desiredOutput = "name: Fred\ngrades:\n algebra: A\n physics: C+\n literature: B"; - } - - void NestedFlowMap(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::Flow; - out << YAML::BeginMap; - out << YAML::Key << "name"; - out << YAML::Value << "Fred"; - out << YAML::Key << "grades"; - out << YAML::Value; - out << YAML::BeginMap; - out << YAML::Key << "algebra" << YAML::Value << "A"; - out << YAML::Key << "physics" << YAML::Value << "C+"; - out << YAML::Key << "literature" << YAML::Value << "B"; - out << YAML::EndMap; - out << YAML::EndMap; - - desiredOutput = "{name: Fred, grades: {algebra: A, physics: C+, literature: B}}"; - } - - void MapListMix(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginMap; - out << YAML::Key << "name"; - out << YAML::Value << "Bob"; - out << YAML::Key << "position"; - out << YAML::Value; - out << YAML::Flow << YAML::BeginSeq << 2 << 4 << YAML::EndSeq; - out << YAML::Key << "invincible" << YAML::Value << YAML::OnOffBool << false; - out << YAML::EndMap; - - desiredOutput = "name: Bob\nposition: [2, 4]\ninvincible: off"; - } - - void SimpleLongKey(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::LongKey; - out << YAML::BeginMap; - out << YAML::Key << "height"; - out << YAML::Value << "5'9\""; - out << YAML::Key << "weight"; - out << YAML::Value << 145; - out << YAML::EndMap; - - desiredOutput = "? height\n: 5'9\"\n? weight\n: 145"; - } - - void SingleLongKey(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::Key << "age"; - out << YAML::Value << "24"; - out << YAML::LongKey << YAML::Key << "height"; - out << YAML::Value << "5'9\""; - out << YAML::Key << "weight"; - out << YAML::Value << 145; - out << YAML::EndMap; - - desiredOutput = "age: 24\n? height\n: 5'9\"\nweight: 145"; - } - - void ComplexLongKey(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::LongKey; - out << YAML::BeginMap; - out << YAML::Key << YAML::BeginSeq << 1 << 3 << YAML::EndSeq; - out << YAML::Value << "monster"; - out << YAML::Key << YAML::Flow << YAML::BeginSeq << 2 << 0 << YAML::EndSeq; - out << YAML::Value << "demon"; - out << YAML::EndMap; - - desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon"; - } - - void AutoLongKey(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::Key << YAML::BeginSeq << 1 << 3 << YAML::EndSeq; - out << YAML::Value << "monster"; - out << YAML::Key << YAML::Flow << YAML::BeginSeq << 2 << 0 << YAML::EndSeq; - out << YAML::Value << "demon"; - out << YAML::Key << "the origin"; - out << YAML::Value << "angel"; - out << YAML::EndMap; - - desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon\nthe origin: angel"; - } - - void ScalarFormat(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginSeq; - out << "simple scalar"; - out << YAML::SingleQuoted << "explicit single-quoted scalar"; - out << YAML::DoubleQuoted << "explicit double-quoted scalar"; - out << "auto-detected\ndouble-quoted scalar"; - out << "a non-\"auto-detected\" double-quoted scalar"; - out << YAML::Literal << "literal scalar\nthat may span\nmany, many\nlines and have \"whatever\" crazy\tsymbols that we like"; - out << YAML::EndSeq; - - desiredOutput = "- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\xadouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like"; - } - - void AutoLongKeyScalar(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::Key << YAML::Literal << "multi-line\nscalar"; - out << YAML::Value << "and its value"; - out << YAML::EndMap; - - desiredOutput = "? |\n multi-line\n scalar\n: and its value"; - } - - void LongKeyFlowMap(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::Flow; - out << YAML::BeginMap; - out << YAML::Key << "simple key"; - out << YAML::Value << "and value"; - out << YAML::LongKey << YAML::Key << "long key"; - out << YAML::Value << "and its value"; - out << YAML::EndMap; - - desiredOutput = "{simple key: and value, ? long key: and its value}"; - } - - void BlockMapAsKey(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::Key; - out << YAML::BeginMap; - out << YAML::Key << "key" << YAML::Value << "value"; - out << YAML::Key << "next key" << YAML::Value << "next value"; - out << YAML::EndMap; - out << YAML::Value; - out << "total value"; - out << YAML::EndMap; - - desiredOutput = "?\n key: value\n next key: next value\n: total value"; - } - - void AliasAndAnchor(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginSeq; - out << YAML::Anchor("fred"); - out << YAML::BeginMap; - out << YAML::Key << "name" << YAML::Value << "Fred"; - out << YAML::Key << "age" << YAML::Value << 42; - out << YAML::EndMap; - out << YAML::Alias("fred"); - out << YAML::EndSeq; - - desiredOutput = "- &fred\n name: Fred\n age: 42\n- *fred"; - } - - void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::Key << "receipt"; - out << YAML::Value << "Oz-Ware Purchase Invoice"; - out << YAML::Key << "date"; - out << YAML::Value << "2007-08-06"; - out << YAML::Key << "customer"; - out << YAML::Value; - out << YAML::BeginMap; - out << YAML::Key << "given"; - out << YAML::Value << "Dorothy"; - out << YAML::Key << "family"; - out << YAML::Value << "Gale"; - out << YAML::EndMap; - out << YAML::Key << "items"; - out << YAML::Value; - out << YAML::BeginSeq; - out << YAML::BeginMap; - out << YAML::Key << "part_no"; - out << YAML::Value << "A4786"; - out << YAML::Key << "descrip"; - out << YAML::Value << "Water Bucket (Filled)"; - out << YAML::Key << "price"; - out << YAML::Value << 1.47; - out << YAML::Key << "quantity"; - out << YAML::Value << 4; - out << YAML::EndMap; - out << YAML::BeginMap; - out << YAML::Key << "part_no"; - out << YAML::Value << "E1628"; - out << YAML::Key << "descrip"; - out << YAML::Value << "High Heeled \"Ruby\" Slippers"; - out << YAML::Key << "price"; - out << YAML::Value << 100.27; - out << YAML::Key << "quantity"; - out << YAML::Value << 1; - out << YAML::EndMap; - out << YAML::EndSeq; - out << YAML::Key << "bill-to"; - out << YAML::Value << YAML::Anchor("id001"); - out << YAML::BeginMap; - out << YAML::Key << "street"; - out << YAML::Value << YAML::Literal << "123 Tornado Alley\nSuite 16"; - out << YAML::Key << "city"; - out << YAML::Value << "East Westville"; - out << YAML::Key << "state"; - out << YAML::Value << "KS"; - out << YAML::EndMap; - out << YAML::Key << "ship-to"; - out << YAML::Value << YAML::Alias("id001"); - out << YAML::EndMap; - - desiredOutput = "receipt: Oz-Ware Purchase Invoice\ndate: 2007-08-06\ncustomer:\n given: Dorothy\n family: Gale\nitems:\n -\n part_no: A4786\n descrip: Water Bucket (Filled)\n price: 1.47\n quantity: 4\n -\n part_no: E1628\n descrip: High Heeled \"Ruby\" Slippers\n price: 100.27\n quantity: 1\nbill-to: &id001\n street: |\n 123 Tornado Alley\n Suite 16\n city: East Westville\n state: KS\nship-to: *id001"; - } - - void STLContainers(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginSeq; - std::vector primes; - primes.push_back(2); - primes.push_back(3); - primes.push_back(5); - primes.push_back(7); - primes.push_back(11); - primes.push_back(13); - out << YAML::Flow << primes; - std::map ages; - ages["Daniel"] = 26; - ages["Jesse"] = 24; - out << ages; - out << YAML::EndSeq; - - desiredOutput = "- [2, 3, 5, 7, 11, 13]\n-\n Daniel: 26\n Jesse: 24"; - } - - void SimpleComment(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::Key << "method"; - out << YAML::Value << "least squares" << YAML::Comment("should we change this method?"); - out << YAML::EndMap; - - desiredOutput = "method: least squares # should we change this method?"; - } - - void MultiLineComment(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginSeq; - out << "item 1" << YAML::Comment("really really long\ncomment that couldn't possibly\nfit on one line"); - out << "item 2"; - out << YAML::EndSeq; - - desiredOutput = "- item 1 # really really long\n # comment that couldn't possibly\n # fit on one line\n- item 2"; - } - - void ComplexComments(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::LongKey << YAML::Key << "long key" << YAML::Comment("long key"); - out << YAML::Value << "value"; - out << YAML::EndMap; - - desiredOutput = "? long key # long key\n: value"; - } - - void Indentation(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::Indent(4); - out << YAML::BeginSeq; - out << YAML::BeginMap; - out << YAML::Key << "key 1" << YAML::Value << "value 1"; - out << YAML::Key << "key 2" << YAML::Value << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; - out << YAML::EndMap; - out << YAML::EndSeq; - - desiredOutput = "-\n key 1: value 1\n key 2:\n - a\n - b\n - c"; - } - - void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) - { - out.SetIndent(4); - out.SetMapFormat(YAML::LongKey); - - out << YAML::BeginSeq; - out << YAML::BeginMap; - out << YAML::Key << "key 1" << YAML::Value << "value 1"; - out << YAML::Key << "key 2" << YAML::Value << YAML::Flow << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; - out << YAML::EndMap; - out << YAML::EndSeq; - - desiredOutput = "-\n ? key 1\n : value 1\n ? key 2\n : [a, b, c]"; - } - - void ComplexGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginSeq; - out << YAML::Block; - out << YAML::BeginMap; - out << YAML::Key << "key 1" << YAML::Value << "value 1"; - out << YAML::Key << "key 2" << YAML::Value; - out.SetSeqFormat(YAML::Flow); - out << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; - out << YAML::EndMap; - out << YAML::BeginMap; - out << YAML::Key << YAML::BeginSeq << 1 << 2 << YAML::EndSeq; - out << YAML::Value << YAML::BeginMap << YAML::Key << "a" << YAML::Value << "b" << YAML::EndMap; - out << YAML::EndMap; - out << YAML::EndSeq; - - desiredOutput = "-\n key 1: value 1\n key 2: [a, b, c]\n-\n ? [1, 2]\n :\n a: b"; - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////// - // incorrect emitting - - void ExtraEndSeq(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::UNEXPECTED_END_SEQ; - - out << YAML::BeginSeq; - out << "Hello"; - out << "World"; - out << YAML::EndSeq; - out << YAML::EndSeq; - } - - void ExtraEndMap(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::UNEXPECTED_END_MAP; - - out << YAML::BeginMap; - out << YAML::Key << "Hello" << YAML::Value << "World"; - out << YAML::EndMap; - out << YAML::EndMap; - } - - void BadSingleQuoted(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::SINGLE_QUOTED_CHAR; - - out << YAML::SingleQuoted << "Hello\nWorld"; - } - - void InvalidAnchor(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::INVALID_ANCHOR; - - out << YAML::BeginSeq; - out << YAML::Anchor("new\nline") << "Test"; - out << YAML::EndSeq; - } - - void InvalidAlias(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::INVALID_ALIAS; - - out << YAML::BeginSeq; - out << YAML::Alias("new\nline"); - out << YAML::EndSeq; - } - - void MissingKey(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::EXPECTED_KEY_TOKEN; - - out << YAML::BeginMap; - out << YAML::Key << "key" << YAML::Value << "value"; - out << "missing key" << YAML::Value << "value"; - out << YAML::EndMap; - } - - void MissingValue(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::EXPECTED_VALUE_TOKEN; - - out << YAML::BeginMap; - out << YAML::Key << "key" << "value"; - out << YAML::EndMap; - } - - void UnexpectedKey(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::UNEXPECTED_KEY_TOKEN; - - out << YAML::BeginSeq; - out << YAML::Key << "hi"; - out << YAML::EndSeq; - } - - void UnexpectedValue(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::UNEXPECTED_VALUE_TOKEN; - - out << YAML::BeginSeq; - out << YAML::Value << "hi"; - out << YAML::EndSeq; - } - } } diff --git a/yaml-reader/tests.h b/yaml-reader/tests.h index a062a09..fb33c24 100644 --- a/yaml-reader/tests.h +++ b/yaml-reader/tests.h @@ -3,10 +3,32 @@ namespace YAML { class Emitter; } namespace Test { - void RunAll(bool verbose); - bool Inout(const std::string& file, bool verbose); + void RunAll(); + bool RunParserTests(); bool RunEmitterTests(); + + namespace Parser { + // scalar tests + void SimpleScalar(std::string& inputScalar, std::string& desiredOutput); + void MultiLineScalar(std::string& inputScalar, std::string& desiredOutput); + void LiteralScalar(std::string& inputScalar, std::string& desiredOutput); + void FoldedScalar(std::string& inputScalar, std::string& desiredOutput); + void ChompedFoldedScalar(std::string& inputScalar, std::string& desiredOutput); + void ChompedLiteralScalar(std::string& inputScalar, std::string& desiredOutput); + void FoldedScalarWithIndent(std::string& inputScalar, std::string& desiredOutput); + void ColonScalar(std::string& inputScalar, std::string& desiredOutput); + void QuotedScalar(std::string& inputScalar, std::string& desiredOutput); + void CommaScalar(std::string& inputScalar, std::string& desiredOutput); + void DashScalar(std::string& inputScalar, std::string& desiredOutput); + void URLScalar(std::string& inputScalar, std::string& desiredOutput); + + // misc tests + bool SimpleSeq(); + bool SimpleMap(); + bool FlowSeq(); + bool FlowMap(); + } namespace Emitter { // correct emitting diff --git a/yaml-reader/tests/directives.yaml b/yaml-reader/tests/directives.yaml deleted file mode 100644 index 5e81cdd..0000000 --- a/yaml-reader/tests/directives.yaml +++ /dev/null @@ -1,5 +0,0 @@ -%YAML 1.2 -%TAG ! !howdy ---- -- basic node -- ! yeah baby diff --git a/yaml-reader/tests/mixed.yaml b/yaml-reader/tests/mixed.yaml deleted file mode 100644 index 68cbf4a..0000000 --- a/yaml-reader/tests/mixed.yaml +++ /dev/null @@ -1,32 +0,0 @@ -- the main thing is a sequence -- here's a key: value - and another: value -- let's inline: [1, 2, 3] - and an inline map: {key: value, 243: 101} -- and multiple indents: - - here's - - a - - list - and another: - - list - - of - - things -- maybe now: - let's: get - pretty: - deep: here - in: - the: nesting - just: to - confuse: - the: heck - out: - - of - - the: parser - if: - - we - - can - - do: that - what: do - you: think? - \ No newline at end of file diff --git a/yaml-reader/tests/scalars.yaml b/yaml-reader/tests/scalars.yaml deleted file mode 100644 index 65f9a06..0000000 --- a/yaml-reader/tests/scalars.yaml +++ /dev/null @@ -1,35 +0,0 @@ -- normal scalar, but - over several lines -- | - literal scalar - so we can draw ASCII: - - - - - | - | - ------ -- > - and a folded scalar... so we - can just keep writing various - things. And if we want to keep indentation: - - we just indent a little - see, this stays indented -- >- - Here's a folded scalar - that gets chomped. -- |- - And here's a literal scalar - that gets chomped. -- >2 - Here's a folded scalar - that starts with some indentation. -- ::vector -- ": - ()" -- Up, up, and away! -- -123 -- http://example.com/foo#bar -# Inside flow collection: -- [ ::vector, - ": - ()", - "Up, up and away!", - -123, - http://example.com/foo#bar ] \ No newline at end of file diff --git a/yaml-reader/tests/simple.yaml b/yaml-reader/tests/simple.yaml deleted file mode 100644 index 69d4239..0000000 --- a/yaml-reader/tests/simple.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -just a scalar ---- -and another scalar ---- -now an end document -... ---- -and now two -... -... ---- -and that's it \ No newline at end of file diff --git a/yaml-reader/tests/test.yaml b/yaml-reader/tests/test.yaml deleted file mode 100644 index c914749..0000000 --- a/yaml-reader/tests/test.yaml +++ /dev/null @@ -1,4 +0,0 @@ -- true -- false -- y -- n \ No newline at end of file From 6e1fc798e137cda4945a412df5a95ab94ae1c5f4 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sun, 31 May 2009 06:39:08 +0000 Subject: [PATCH 102/295] Updated yaml-reader CMake file --- yaml-reader/CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/yaml-reader/CMakeLists.txt b/yaml-reader/CMakeLists.txt index 866bfe0..f2c3ce2 100644 --- a/yaml-reader/CMakeLists.txt +++ b/yaml-reader/CMakeLists.txt @@ -1,6 +1,10 @@ -set(yaml-reader_sources main.cpp tests.cpp) +file(GLOB yaml-reader_headers *.h) +file(GLOB yaml-reader_sources *.cpp) -add_executable(yaml-reader ${yaml-reader_sources}) +add_executable(yaml-reader + ${yaml-reader_sources} + ${yaml-reader_headers} +) target_link_libraries(yaml-reader yaml-cpp) add_test(yaml-reader-test yaml-reader) From ed8f016c1f8c3bf5f470cd3d178afca8ab21e020 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 1 Jun 2009 03:42:16 +0000 Subject: [PATCH 103/295] Updated the nested RegEx classes so they don't need to also take an std::string --- src/regex.cpp | 83 +++++++-------------------------------------------- src/regex.h | 7 ----- 2 files changed, 10 insertions(+), 80 deletions(-) diff --git a/src/regex.cpp b/src/regex.cpp index 4ffd711..b48036e 100644 --- a/src/regex.cpp +++ b/src/regex.cpp @@ -106,12 +106,19 @@ namespace YAML // . Returns -1 if no characters were matched (the reason for // not returning zero is that we may have an empty regex // which is ALWAYS successful at matching zero characters). - int RegEx::Match(const std::string& str) const + // . REMEMBER that we only match from the start of the buffer! + int RegEx::Match(const Buffer& buffer) const { if(!m_pOp) - return str.empty() ? 0 : -1; // the empty regex only is successful on the empty string + return !buffer ? 0 : -1; // the empty regex only is successful on the empty string - return m_pOp->Match(str, *this); + return m_pOp->Match(buffer, *this); + } + + int RegEx::Match(const std::string& str) const + { + Buffer buffer(str.c_str(), str.size()); + return Match(buffer); } // Match @@ -119,17 +126,6 @@ namespace YAML { return Match(in.current()); } - - // Match - // . The buffer version does the same thing as the string version; - // REMEMBER that we only match from the start of the buffer! - int RegEx::Match(const Buffer& buffer) const - { - if(!m_pOp) - return !buffer ? 0 : -1; // see above - - return m_pOp->Match(buffer, *this); - } RegEx operator ! (const RegEx& ex) { @@ -166,14 +162,6 @@ namespace YAML // Operators // MatchOperator - int RegEx::MatchOperator::Match(const std::string& str, const RegEx& regex) const - { - if(str.empty() || str[0] != regex.m_a) - return -1; - return 1; - } - - int RegEx::MatchOperator::Match(const Buffer& buffer, const RegEx& regex) const { if(!buffer || buffer[0] != regex.m_a) @@ -182,13 +170,6 @@ namespace YAML } // RangeOperator - int RegEx::RangeOperator::Match(const std::string& str, const RegEx& regex) const - { - if(str.empty() || regex.m_a > str[0] || regex.m_z < str[0]) - return -1; - return 1; - } - int RegEx::RangeOperator::Match(const Buffer& buffer, const RegEx& regex) const { if(!buffer || regex.m_a > buffer[0] || regex.m_z < buffer[0]) @@ -197,16 +178,6 @@ namespace YAML } // OrOperator - int RegEx::OrOperator::Match(const std::string& str, const RegEx& regex) const - { - for(unsigned i=0;i= 0) - return n; - } - return -1; - } - int RegEx::OrOperator::Match(const Buffer& buffer, const RegEx& regex) const { for(unsigned i=0;i= 0) - return -1; - return 1; - } - int RegEx::NotOperator::Match(const Buffer& buffer, const RegEx& regex) const { if(regex.m_params.empty()) @@ -267,18 +216,6 @@ namespace YAML } // SeqOperator - int RegEx::SeqOperator::Match(const std::string& str, const RegEx& regex) const - { - int offset = 0; - for(unsigned i=0;i Date: Fri, 12 Jun 2009 04:28:36 +0000 Subject: [PATCH 104/295] Patched CMake file to allow flexibility in build (in particular to allow shared lib build) --- CMakeLists.txt | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d75d3f..3e902bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,8 +4,18 @@ project (YAML_CPP) enable_testing() -set(LIBRARY_OUTPUT_PATH lib${LIB_SUFFIX}) -set(LIB_INSTALL_DIR lib${LIB_SUFFIX}) +if(WIN32) + set(_library_dir bin) # .dll are in PATH, like executables +else(WIN32) + set(_library_dir lib) +endif(WIN32) +# +set(_INSTALL_DESTINATIONS + RUNTIME DESTINATION bin + LIBRARY DESTINATION ${_library_dir}${LIB_SUFFIX} + ARCHIVE DESTINATION lib${LIB_SUFFIX} +) +# set(INCLUDE_INSTALL_DIR include/yaml-cpp) file(GLOB public_headers include/*.h) @@ -19,11 +29,7 @@ add_library(yaml-cpp ${sources} ) -install( - TARGETS yaml-cpp - LIBRARY ARCHIVE - DESTINATION ${LIB_INSTALL_DIR} -) +install(TARGETS yaml-cpp ${_INSTALL_DESTINATIONS}) install( FILES ${public_headers} DESTINATION ${INCLUDE_INSTALL_DIR} From aa959e670560e6c41554e93490fca4eb09cd8483 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 25 Jun 2009 03:05:09 +0000 Subject: [PATCH 105/295] Fixed bug that didn't allow multiple docs in a stream (using only "---") --- src/scantoken.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scantoken.cpp b/src/scantoken.cpp index 0a6b329..4735a1a 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -59,7 +59,7 @@ namespace YAML // DocStart void Scanner::ScanDocStart() { - PopIndentTo(INPUT.column); + PopIndentTo(-1); VerifyAllSimpleKeys(); m_simpleKeyAllowed = false; From e7f1ca7fb1833bb3358f4b40b023e77622ebfaf4 Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 10 Jul 2009 03:10:03 +0000 Subject: [PATCH 106/295] Merged utf branch changes r178:187 into the trunk --- CMakeLists.txt | 4 +- src/emitterutils.cpp | 5 +- src/regex.cpp | 202 ++------------------ src/regex.h | 71 +++---- src/regeximpl.h | 172 +++++++++++++++++ src/stream.cpp | 415 +++++++++++++++++++++++++++++++++++++++-- src/stream.h | 58 ++++-- src/streamcharsource.h | 39 ++++ src/stringsource.h | 34 ++++ util/CMakeLists.txt | 2 + util/parse.cpp | 21 +++ yaml-reader/tests.cpp | 179 ++++++++++++++++++ yamlcpp.vcproj | 8 + 13 files changed, 939 insertions(+), 271 deletions(-) create mode 100644 src/regeximpl.h create mode 100644 src/streamcharsource.h create mode 100644 src/stringsource.h create mode 100644 util/CMakeLists.txt create mode 100644 util/parse.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e902bc..9b1856f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 2.6) project (YAML_CPP) +SET(CMAKE_CXX_FLAGS "-O2") + enable_testing() if(WIN32) @@ -36,4 +38,4 @@ install( ) add_subdirectory (yaml-reader) - +add_subdirectory (util) diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index 1779a9b..2fc6ad7 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -3,6 +3,7 @@ #include "indentation.h" #include "exceptions.h" #include +#include "stringsource.h" namespace YAML { @@ -29,8 +30,8 @@ namespace YAML || (!Exp::Printable) || Exp::Break || Exp::Tab; - Buffer buffer(&str[0], str.size()); - while(buffer.size) { + StringCharSource buffer(str.c_str(), str.size()); + while(buffer) { if(disallowed.Matches(buffer)) return false; ++buffer; diff --git a/src/regex.cpp b/src/regex.cpp index b48036e..d26cdb6 100644 --- a/src/regex.cpp +++ b/src/regex.cpp @@ -1,139 +1,39 @@ #include "crt.h" #include "regex.h" -#include "stream.h" -#include namespace YAML { - RegEx::RegEx(REGEX_OP op): m_op(op), m_pOp(0) + // constructors + RegEx::RegEx(): m_op(REGEX_EMPTY) { - SetOp(); } - - RegEx::RegEx(const RegEx& rhs): m_pOp(0) + + RegEx::RegEx(REGEX_OP op): m_op(op) { - m_op = rhs.m_op; - m_a = rhs.m_a; - m_z = rhs.m_z; - m_params = rhs.m_params; - - SetOp(); } - - RegEx::RegEx(): m_op(REGEX_EMPTY), m_pOp(0) + + RegEx::RegEx(char ch): m_op(REGEX_MATCH), m_a(ch) { - SetOp(); } - - RegEx::RegEx(char ch): m_op(REGEX_MATCH), m_pOp(0), m_a(ch) + + RegEx::RegEx(char a, char z): m_op(REGEX_RANGE), m_a(a), m_z(z) { - SetOp(); } - - RegEx::RegEx(char a, char z): m_op(REGEX_RANGE), m_pOp(0), m_a(a), m_z(z) - { - SetOp(); - } - - RegEx::RegEx(const std::string& str, REGEX_OP op): m_op(op), m_pOp(0) + + RegEx::RegEx(const std::string& str, REGEX_OP op): m_op(op) { for(unsigned i=0;i= 0; - } - - bool RegEx::Matches(const Buffer& buffer) const - { - return Match(buffer) >= 0; } - bool RegEx::Matches(const Stream& in) const - { - return Match(in) >= 0; - } - - // Match - // . Matches the given string against this regular expression. - // . Returns the number of characters matched. - // . Returns -1 if no characters were matched (the reason for - // not returning zero is that we may have an empty regex - // which is ALWAYS successful at matching zero characters). - // . REMEMBER that we only match from the start of the buffer! - int RegEx::Match(const Buffer& buffer) const - { - if(!m_pOp) - return !buffer ? 0 : -1; // the empty regex only is successful on the empty string - - return m_pOp->Match(buffer, *this); - } - - int RegEx::Match(const std::string& str) const - { - Buffer buffer(str.c_str(), str.size()); - return Match(buffer); - } - - // Match - int RegEx::Match(const Stream& in) const - { - return Match(in.current()); - } - + // combination constructors RegEx operator ! (const RegEx& ex) { RegEx ret(REGEX_NOT); ret.m_params.push_back(ex); return ret; } - + RegEx operator || (const RegEx& ex1, const RegEx& ex2) { RegEx ret(REGEX_OR); @@ -141,7 +41,7 @@ namespace YAML ret.m_params.push_back(ex2); return ret; } - + RegEx operator && (const RegEx& ex1, const RegEx& ex2) { RegEx ret(REGEX_AND); @@ -149,85 +49,13 @@ namespace YAML ret.m_params.push_back(ex2); return ret; } - + RegEx operator + (const RegEx& ex1, const RegEx& ex2) { RegEx ret(REGEX_SEQ); ret.m_params.push_back(ex1); ret.m_params.push_back(ex2); return ret; - } - - ////////////////////////////////////////////////////////////////////////////// - // Operators - - // MatchOperator - int RegEx::MatchOperator::Match(const Buffer& buffer, const RegEx& regex) const - { - if(!buffer || buffer[0] != regex.m_a) - return -1; - return 1; - } - - // RangeOperator - int RegEx::RangeOperator::Match(const Buffer& buffer, const RegEx& regex) const - { - if(!buffer || regex.m_a > buffer[0] || regex.m_z < buffer[0]) - return -1; - return 1; - } - - // OrOperator - int RegEx::OrOperator::Match(const Buffer& buffer, const RegEx& regex) const - { - for(unsigned i=0;i= 0) - return n; - } - return -1; - } - - // AndOperator - // Note: 'AND' is a little funny, since we may be required to match things - // of different lengths. If we find a match, we return the length of - // the FIRST entry on the list. - int RegEx::AndOperator::Match(const Buffer& buffer, const RegEx& regex) const - { - int first = -1; - for(unsigned i=0;i= 0) - return -1; - return 1; - } - - // SeqOperator - int RegEx::SeqOperator::Match(const Buffer& buffer, const RegEx& regex) const - { - int offset = 0; - for(unsigned i=0;i bool Matches(const Source& source) const; + + int Match(const std::string& str) const; + int Match(const Stream& in) const; private: RegEx(REGEX_OP op); - void SetOp(); + + template bool IsValidSource(const Source& source) const; + template int Match(const Source& source) const; + template int MatchUnchecked(const Source& source) const; + + template int MatchOpEmpty(const Source& source) const; + template int MatchOpMatch(const Source& source) const; + template int MatchOpRange(const Source& source) const; + template int MatchOpOr(const Source& source) const; + template int MatchOpAnd(const Source& source) const; + template int MatchOpNot(const Source& source) const; + template int MatchOpSeq(const Source& source) const; private: REGEX_OP m_op; - Operator *m_pOp; char m_a, m_z; std::vector m_params; }; } + +#include "regeximpl.h" diff --git a/src/regeximpl.h b/src/regeximpl.h new file mode 100644 index 0000000..f2daa43 --- /dev/null +++ b/src/regeximpl.h @@ -0,0 +1,172 @@ +#pragma once + +#include "stream.h" +#include "stringsource.h" +#include "streamcharsource.h" + +namespace YAML +{ + // query matches + inline bool RegEx::Matches(char ch) const { + std::string str; + str += ch; + return Matches(str); + } + + inline bool RegEx::Matches(const std::string& str) const { + return Match(str) >= 0; + } + + inline bool RegEx::Matches(const Stream& in) const { + return Match(in) >= 0; + } + + template + inline bool RegEx::Matches(const Source& source) const { + return Match(source) >= 0; + } + + // Match + // . Matches the given string against this regular expression. + // . Returns the number of characters matched. + // . Returns -1 if no characters were matched (the reason for + // not returning zero is that we may have an empty regex + // which is ALWAYS successful at matching zero characters). + // . REMEMBER that we only match from the start of the buffer! + inline int RegEx::Match(const std::string& str) const + { + StringCharSource source(str.c_str(), str.size()); + return Match(source); + } + + inline int RegEx::Match(const Stream& in) const + { + StreamCharSource source(in); + return Match(source); + } + + template + inline bool RegEx::IsValidSource(const Source& source) const + { + return source; + } + + template<> + inline bool RegEx::IsValidSource(const StringCharSource&source) const + { + return source || m_op == REGEX_EMPTY; + } + + template + inline int RegEx::Match(const Source& source) const + { + return IsValidSource(source) ? MatchUnchecked(source) : -1; + } + + template + inline int RegEx::MatchUnchecked(const Source& source) const + { + switch(m_op) { + case REGEX_EMPTY: + return MatchOpEmpty(source); + case REGEX_MATCH: + return MatchOpMatch(source); + case REGEX_RANGE: + return MatchOpRange(source); + case REGEX_OR: + return MatchOpOr(source); + case REGEX_AND: + return MatchOpAnd(source); + case REGEX_NOT: + return MatchOpNot(source); + case REGEX_SEQ: + return MatchOpSeq(source); + } + + return -1; + } + + ////////////////////////////////////////////////////////////////////////////// + // Operators + // Note: the convention MatchOp* is that we can assume IsSourceValid(source). + // So we do all our checks *before* we call these functions + + // EmptyOperator + template + inline int RegEx::MatchOpEmpty(const Source& source) const { + return source[0] == Stream::eof() ? 0 : -1; + } + + template <> + inline int RegEx::MatchOpEmpty(const StringCharSource& source) const { + return !source ? 0 : -1; // the empty regex only is successful on the empty string + } + + // MatchOperator + template + inline int RegEx::MatchOpMatch(const Source& source) const { + if(source[0] != m_a) + return -1; + return 1; + } + + // RangeOperator + template + inline int RegEx::MatchOpRange(const Source& source) const { + if(m_a > source[0] || m_z < source[0]) + return -1; + return 1; + } + + // OrOperator + template + inline int RegEx::MatchOpOr(const Source& source) const { + for(unsigned i=0;i= 0) + return n; + } + return -1; + } + + // AndOperator + // Note: 'AND' is a little funny, since we may be required to match things + // of different lengths. If we find a match, we return the length of + // the FIRST entry on the list. + template + inline int RegEx::MatchOpAnd(const Source& source) const { + int first = -1; + for(unsigned i=0;i + inline int RegEx::MatchOpNot(const Source& source) const { + if(m_params.empty()) + return -1; + if(m_params[0].MatchUnchecked(source) >= 0) + return -1; + return 1; + } + + // SeqOperator + template + inline int RegEx::MatchOpSeq(const Source& source) const { + int offset = 0; + for(unsigned i=0;i +#include "exp.h" + +#ifndef YAML_PREFETCH_SIZE +#define YAML_PREFETCH_SIZE 2048 +#endif + +#define S_ARRAY_SIZE( A ) (sizeof(A)/sizeof(*(A))) +#define S_ARRAY_END( A ) ((A) + S_ARRAY_SIZE(A)) + +#define CP_REPLACEMENT_CHARACTER (0xFFFD) namespace YAML { - Stream::Stream(std::istream& input): pos(0), line(0), column(0), size(0), buffer(0) + enum UtfIntroState { + uis_start, + uis_utfbe_b1, + uis_utf32be_b2, + uis_utf32be_bom3, + uis_utf32be, + uis_utf16be, + uis_utf16be_bom1, + uis_utfle_bom1, + uis_utf16le_bom2, + uis_utf32le_bom3, + uis_utf16le, + uis_utf32le, + uis_utf8_imp, + uis_utf16le_imp, + uis_utf32le_imp3, + uis_utf8_bom1, + uis_utf8_bom2, + uis_utf8, + uis_error + }; + + enum UtfIntroCharType { + uict00, + uictBB, + uictBF, + uictEF, + uictFE, + uictFF, + uictAscii, + uictOther, + uictMax + }; + + static bool s_introFinalState[] = { + false, //uis_start + false, //uis_utfbe_b1 + false, //uis_utf32be_b2 + false, //uis_utf32be_bom3 + true, //uis_utf32be + true, //uis_utf16be + false, //uis_utf16be_bom1 + false, //uis_utfle_bom1 + false, //uis_utf16le_bom2 + false, //uis_utf32le_bom3 + true, //uis_utf16le + true, //uis_utf32le + false, //uis_utf8_imp + false, //uis_utf16le_imp + false, //uis_utf32le_imp3 + false, //uis_utf8_bom1 + false, //uis_utf8_bom2 + true, //uis_utf8 + true, //uis_error + }; + + static UtfIntroState s_introTransitions[][uictMax] = { + // uict00, uictBB, uictBF, uictEF, uictFE, uictFF, uictAscii, uictOther + {uis_utfbe_b1, uis_utf8, uis_utf8, uis_utf8_bom1, uis_utf16be_bom1, uis_utfle_bom1, uis_utf8_imp, uis_utf8}, + {uis_utf32be_b2, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf16be, uis_utf8}, + {uis_utf32be, uis_utf8, uis_utf8, uis_utf8, uis_utf32be_bom3, uis_utf8, uis_utf8, uis_utf8}, + {uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf32be, uis_utf8, uis_utf8}, + {uis_utf32be, uis_utf32be, uis_utf32be, uis_utf32be, uis_utf32be, uis_utf32be, uis_utf32be, uis_utf32be}, + {uis_utf16be, uis_utf16be, uis_utf16be, uis_utf16be, uis_utf16be, uis_utf16be, uis_utf16be, uis_utf16be}, + {uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf16be, uis_utf8, uis_utf8}, + {uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf16le_bom2, uis_utf8, uis_utf8, uis_utf8}, + {uis_utf32le_bom3, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le}, + {uis_utf32le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le}, + {uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le}, + {uis_utf32le, uis_utf32le, uis_utf32le, uis_utf32le, uis_utf32le, uis_utf32le, uis_utf32le, uis_utf32le}, + {uis_utf16le_imp, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8}, + {uis_utf32le_imp3, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le}, + {uis_utf32le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le}, + {uis_utf8, uis_utf8_bom2, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8}, + {uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8}, + {uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8}, + }; + + static char s_introUngetCount[][uictMax] = { + // uict00, uictBB, uictBF, uictEF, uictFE, uictFF, uictAscii, uictOther + {0, 1, 1, 0, 0, 0, 0, 1}, + {0, 2, 2, 2, 2, 2, 2, 2}, + {3, 3, 3, 3, 0, 3, 3, 3}, + {4, 4, 4, 4, 4, 0, 4, 4}, + {1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 1}, + {2, 2, 2, 2, 2, 0, 2, 2}, + {2, 2, 2, 2, 0, 2, 2, 2}, + {0, 1, 1, 1, 1, 1, 1, 1}, + {0, 2, 2, 2, 2, 2, 2, 2}, + {1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 1}, + {0, 2, 2, 2, 2, 2, 2, 2}, + {0, 3, 3, 3, 3, 3, 3, 3}, + {4, 4, 4, 4, 4, 4, 4, 4}, + {2, 0, 2, 2, 2, 2, 2, 2}, + {3, 3, 0, 3, 3, 3, 3, 3}, + {1, 1, 1, 1, 1, 1, 1, 1}, + }; + + inline UtfIntroCharType IntroCharTypeOf(std::istream::int_type ch) { + if (std::istream::traits_type::eof() == ch) { + return uictOther; + } + + switch (ch) { + case 0: return uict00; + case 0xBB: return uictBB; + case 0xBF: return uictBF; + case 0xEF: return uictEF; + case 0xFE: return uictFE; + case 0xFF: return uictFF; + } + + if ((ch > 0) && (ch < 0xFF)) { + return uictAscii; + } + + return uictOther; + } + + inline char Utf8Adjust(unsigned long ch, unsigned char lead_bits, unsigned char rshift) + { + const unsigned char header = ((1 << lead_bits) - 1) << (8 - lead_bits); + const unsigned char mask = (0xFF >> (lead_bits + 1)); + return static_cast(static_cast( + header | ((ch >> rshift) & mask) + )); + } + + inline void QueueUnicodeCodepoint(std::deque& q, unsigned long ch) + { + // We are not allowed to queue the Stream::eof() codepoint, so + // replace it with CP_REPLACEMENT_CHARACTER + if (static_cast(Stream::eof()) == ch) + { + ch = CP_REPLACEMENT_CHARACTER; + } + + if (ch < 0x80) + { + q.push_back(Utf8Adjust(ch, 0, 0)); + } + else if (ch < 0x800) + { + q.push_back(Utf8Adjust(ch, 2, 6)); + q.push_back(Utf8Adjust(ch, 1, 0)); + } + else if (ch < 0x10000) + { + q.push_back(Utf8Adjust(ch, 3, 12)); + q.push_back(Utf8Adjust(ch, 1, 6)); + q.push_back(Utf8Adjust(ch, 1, 0)); + } + else + { + q.push_back(Utf8Adjust(ch, 4, 18)); + q.push_back(Utf8Adjust(ch, 1, 12)); + q.push_back(Utf8Adjust(ch, 1, 6)); + q.push_back(Utf8Adjust(ch, 1, 0)); + } + } + + Stream::Stream(std::istream& input) + : pos(0), line(0), column(0), m_input(input), m_nPushedBack(0), + m_pPrefetched(new unsigned char[YAML_PREFETCH_SIZE]), + m_nPrefetchedAvailable(0), m_nPrefetchedUsed(0) + { + typedef std::istream::traits_type char_traits; + if(!input) return; - std::streambuf *pBuf = input.rdbuf(); + // Determine (or guess) the character-set by reading the BOM, if any. See + // the YAML specification for the determination algorithm. + char_traits::int_type intro[4]; + int nIntroUsed = 0; + UtfIntroState state = uis_start; + for (; !s_introFinalState[state]; ) { + std::istream::int_type ch = input.get(); + intro[nIntroUsed++] = ch; + UtfIntroCharType charType = IntroCharTypeOf(ch); + UtfIntroState newState = s_introTransitions[state][charType]; + int nUngets = s_introUngetCount[state][charType]; + if (nUngets > 0) { + for (; nUngets > 0; --nUngets) { + if (char_traits::eof() != intro[--nIntroUsed]) { + m_bufPushback[m_nPushedBack++] = + char_traits::to_char_type(intro[nIntroUsed]); + } + } + } + state = newState; + } - // store entire file in buffer - size = pBuf->pubseekoff(0, std::ios::end, std::ios::in); - pBuf->pubseekpos(0, std::ios::in); - buffer = new char[size]; - size = pBuf->sgetn(buffer, size); // Note: when reading a Windows CR/LF file, - // pubseekoff() counts CR/LF as two characters, - // setgn() reads CR/LF as a single LF character! + switch (state) { + case uis_utf8: m_charSet = utf8; break; + case uis_utf16le: m_charSet = utf16le; break; + case uis_utf16be: m_charSet = utf16be; break; + case uis_utf32le: m_charSet = utf32le; break; + case uis_utf32be: m_charSet = utf32be; break; + default: m_charSet = utf8; break; + } + + ReadAheadTo(0); } Stream::~Stream() { - delete [] buffer; + delete[] m_pPrefetched; } - - char Stream::peek() + char Stream::peek() const { - return buffer[pos]; + if (m_readahead.empty()) + { + return Stream::eof(); + } + + return m_readahead[0]; } Stream::operator bool() const { - return pos < size; + return m_input.good() || (!m_readahead.empty() && m_readahead[0] != Stream::eof()); } // get // . Extracts a character from the stream and updates our position char Stream::get() { - char ch = buffer[pos]; - pos++; + char ch = peek(); + AdvanceCurrent(); column++; + if(ch == '\n') { column = 0; line++; } + return ch; } @@ -69,4 +277,179 @@ namespace YAML get(); } + void Stream::AdvanceCurrent() + { + if (!m_readahead.empty()) + { + m_readahead.pop_front(); + ++pos; + } + + ReadAheadTo(0); + } + + bool Stream::_ReadAheadTo(size_t i) const + { + while (m_input.good() && (m_readahead.size() <= i)) + { + switch (m_charSet) + { + case utf8: StreamInUtf8(); break; + case utf16le: StreamInUtf16(); break; + case utf16be: StreamInUtf16(); break; + case utf32le: StreamInUtf32(); break; + case utf32be: StreamInUtf32(); break; + } + } + + // signal end of stream + if(!m_input.good()) + m_readahead.push_back(Stream::eof()); + + return m_readahead.size() > i; + } + + void Stream::StreamInUtf8() const + { + unsigned char b = GetNextByte(); + if (m_input.good()) + { + m_readahead.push_back(b); + } + } + + void Stream::StreamInUtf16() const + { + unsigned long ch = 0; + unsigned char bytes[2]; + int nBigEnd = (m_charSet == utf16be) ? 0 : 1; + + bytes[0] = GetNextByte(); + bytes[1] = GetNextByte(); + if (!m_input.good()) + { + return; + } + ch = (static_cast(bytes[nBigEnd]) << 8) | + static_cast(bytes[1 ^ nBigEnd]); + + if (ch >= 0xDC00 && ch < 0xE000) + { + // Trailing (low) surrogate...ugh, wrong order + QueueUnicodeCodepoint(m_readahead, CP_REPLACEMENT_CHARACTER); + return; + } + else if (ch >= 0xD800 && ch < 0xDC00) + { + // ch is a leading (high) surrogate + + // Four byte UTF-8 code point + + // Read the trailing (low) surrogate + for (;;) + { + bytes[0] = GetNextByte(); + bytes[1] = GetNextByte(); + if (!m_input.good()) + { + QueueUnicodeCodepoint(m_readahead, CP_REPLACEMENT_CHARACTER); + return; + } + unsigned long chLow = (static_cast(bytes[nBigEnd]) << 8) | + static_cast(bytes[1 ^ nBigEnd]); + if (chLow < 0xDC00 || ch >= 0xE000) + { + // Trouble...not a low surrogate. Dump a REPLACEMENT CHARACTER into the stream. + QueueUnicodeCodepoint(m_readahead, CP_REPLACEMENT_CHARACTER); + + // Deal with the next UTF-16 unit + if (chLow < 0xD800 || ch >= 0xE000) + { + // Easiest case: queue the codepoint and return + QueueUnicodeCodepoint(m_readahead, ch); + return; + } + else + { + // Start the loop over with the new high surrogate + ch = chLow; + continue; + } + } + + // Select the payload bits from the high surrogate + ch &= 0x3FF; + ch <<= 10; + + // Include bits from low surrogate + ch |= (chLow & 0x3FF); + + // Add the surrogacy offset + ch += 0x10000; + } + } + + QueueUnicodeCodepoint(m_readahead, ch); + } + + inline char* ReadBuffer(unsigned char* pBuffer) + { + return reinterpret_cast(pBuffer); + } + + unsigned char Stream::GetNextByte() const + { + if (m_nPushedBack) + { + return m_bufPushback[--m_nPushedBack]; + } + + if (m_nPrefetchedUsed >= m_nPrefetchedAvailable) + { + std::streambuf *pBuf = m_input.rdbuf(); + m_nPrefetchedAvailable = pBuf->sgetn(ReadBuffer(m_pPrefetched), + YAML_PREFETCH_SIZE); + m_nPrefetchedUsed = 0; + if (!m_nPrefetchedAvailable) + { + m_input.setstate(std::ios_base::eofbit); + } + + if (0 == m_nPrefetchedAvailable) + { + return 0; + } + } + + return m_pPrefetched[m_nPrefetchedUsed++]; + } + + void Stream::StreamInUtf32() const + { + static int indexes[2][4] = { + {3, 2, 1, 0}, + {0, 1, 2, 3} + }; + + unsigned long ch = 0; + unsigned char bytes[4]; + int* pIndexes = (m_charSet == utf32be) ? indexes[1] : indexes[0]; + + bytes[0] = GetNextByte(); + bytes[1] = GetNextByte(); + bytes[2] = GetNextByte(); + bytes[3] = GetNextByte(); + if (!m_input.good()) + { + return; + } + + for (int i = 0; i < 4; ++i) + { + ch <<= 8; + ch |= bytes[pIndexes[i]]; + } + + QueueUnicodeCodepoint(m_readahead, ch); + } } diff --git a/src/stream.h b/src/stream.h index 5bc2c11..05fb29c 100644 --- a/src/stream.h +++ b/src/stream.h @@ -1,42 +1,66 @@ #pragma once +#include #include #include +#include +#include namespace YAML { - // a simple buffer wrapper that knows how big it is - struct Buffer { - Buffer(const char *b, int s): buffer(b), size(s) {} - - operator bool() const { return size > 0; } - bool operator !() const { return !static_cast (*this); } - char operator [] (int i) const { return buffer[i]; } - const Buffer operator + (int offset) const { return Buffer(buffer + offset, size - offset); } - Buffer& operator ++ () { ++buffer; --size; return *this; } - - const char *buffer; - int size; - }; + static const size_t MAX_PARSER_PUSHBACK = 8; class Stream { public: + friend class StreamCharSource; + Stream(std::istream& input); ~Stream(); operator bool() const; bool operator !() const { return !static_cast (*this); } - const Buffer current() const { return Buffer(buffer + pos, size - pos); } - char peek(); + char peek() const; char get(); std::string get(int n); void eat(int n = 1); - int pos, line, column, size; + static char eof() { return 0x04; } + + int pos, line, column; private: - char *buffer; + enum CharacterSet {utf8, utf16le, utf16be, utf32le, utf32be}; + + std::istream& m_input; + CharacterSet m_charSet; + unsigned char m_bufPushback[MAX_PARSER_PUSHBACK]; + mutable size_t m_nPushedBack; + mutable std::deque m_readahead; + unsigned char* const m_pPrefetched; + mutable size_t m_nPrefetchedAvailable; + mutable size_t m_nPrefetchedUsed; + + void AdvanceCurrent(); + char CharAt(size_t i) const; + bool ReadAheadTo(size_t i) const; + bool _ReadAheadTo(size_t i) const; + void StreamInUtf8() const; + void StreamInUtf16() const; + void StreamInUtf32() const; + unsigned char GetNextByte() const; }; + + // CharAt + // . Unchecked access + inline char Stream::CharAt(size_t i) const { + return m_readahead[i]; + } + + inline bool Stream::ReadAheadTo(size_t i) const { + if(m_readahead.size() > i) + return true; + return _ReadAheadTo(i); + } } diff --git a/src/streamcharsource.h b/src/streamcharsource.h new file mode 100644 index 0000000..4a1122c --- /dev/null +++ b/src/streamcharsource.h @@ -0,0 +1,39 @@ +#pragma once + +#include + +namespace YAML +{ + class StreamCharSource + { + public: + StreamCharSource(const Stream& stream); + ~StreamCharSource() {} + + operator bool() const; + char operator [] (std::size_t i) const { return m_stream.CharAt(m_offset + i); } + bool operator !() const { return !static_cast(*this); } + + const StreamCharSource operator + (int i) const; + + private: + std::size_t m_offset; + const Stream& m_stream; + }; + + inline StreamCharSource::StreamCharSource(const Stream& stream): m_offset(0), m_stream(stream) { + } + + inline StreamCharSource::operator bool() const { + return m_stream.ReadAheadTo(m_offset); + } + + inline const StreamCharSource StreamCharSource::operator + (int i) const { + StreamCharSource source(*this); + if(static_cast (source.m_offset) + i >= 0) + source.m_offset += i; + else + source.m_offset = 0; + return source; + } +} diff --git a/src/stringsource.h b/src/stringsource.h new file mode 100644 index 0000000..4b892fe --- /dev/null +++ b/src/stringsource.h @@ -0,0 +1,34 @@ +#pragma once + +#include + +namespace YAML +{ + class StringCharSource + { + public: + StringCharSource(const char *str, std::size_t size): m_str(str), m_size(size), m_offset(0) {} + + operator bool() const { return m_offset < m_size; } + char operator [] (std::size_t i) const { return m_str[m_offset + i]; } + bool operator !() const { return !static_cast(*this); } + + const StringCharSource operator + (int i) const { + StringCharSource source(*this); + if(static_cast (source.m_offset) + i >= 0) + source.m_offset += i; + else + source.m_offset = 0; + return source; + } + + StringCharSource& operator ++ () { + ++m_offset; + return *this; + } + private: + const char *m_str; + std::size_t m_size; + std::size_t m_offset; + }; +} diff --git a/util/CMakeLists.txt b/util/CMakeLists.txt new file mode 100644 index 0000000..22339f0 --- /dev/null +++ b/util/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(parse parse.cpp) +target_link_libraries(parse yaml-cpp) diff --git a/util/parse.cpp b/util/parse.cpp new file mode 100644 index 0000000..1632041 --- /dev/null +++ b/util/parse.cpp @@ -0,0 +1,21 @@ +#include "yaml.h" +#include +#include + +int main(int argc, char **argv) +{ + if(argc != 2) { + std::cout << "Usage: " << argv[0] << " input-file\n"; + return 0; + } + + std::ifstream fin(argv[1]); + try { + YAML::Parser parser(fin); + YAML::Node doc; + parser.GetNextDocument(doc); + } catch(const YAML::Exception& e) { + std::cerr << "Error at line " << e.line << ", col " << e.column << ": " << e.msg << "\n"; + } + return 0; +} diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp index 74a2dd2..c4d222e 100644 --- a/yaml-reader/tests.cpp +++ b/yaml-reader/tests.cpp @@ -72,6 +72,174 @@ namespace Test std::cout << "Caught exception: " << error << "\n"; } } + + typedef void (*EncodingFn)(std::ostream&, int); + + inline char Byte(int ch) + { + return static_cast(static_cast(static_cast(ch))); + } + + void EncodeToUtf8(std::ostream& stream, int ch) + { + if (ch <= 0x7F) + { + stream << Byte(ch); + } + else if (ch <= 0x7FF) + { + stream << Byte(0xC0 | (ch >> 6)); + stream << Byte(0x80 | (ch & 0x3F)); + } + else if (ch <= 0xFFFF) + { + stream << Byte(0xE0 | (ch >> 12)); + stream << Byte(0x80 | ((ch >> 6) & 0x3F)); + stream << Byte(0x80 | (ch & 0x3F)); + } + else if (ch <= 0x1FFFFF) + { + stream << Byte(0xF0 | (ch >> 18)); + stream << Byte(0x80 | ((ch >> 12) & 0x3F)); + stream << Byte(0x80 | ((ch >> 6) & 0x3F)); + stream << Byte(0x80 | (ch & 0x3F)); + } + } + + bool SplitUtf16HighChar(std::ostream& stream, EncodingFn encoding, int ch) + { + int biasedValue = ch - 0x10000; + if (biasedValue < 0) + { + return false; + } + int high = 0xD800 | (biasedValue >> 10); + int low = 0xDC00 | (biasedValue & 0x3FF); + encoding(stream, high); + encoding(stream, low); + return true; + } + + void EncodeToUtf16LE(std::ostream& stream, int ch) + { + if (!SplitUtf16HighChar(stream, &EncodeToUtf16LE, ch)) + { + stream << Byte(ch & 0xFF) << Byte(ch >> 8); + } + } + + void EncodeToUtf16BE(std::ostream& stream, int ch) + { + if (!SplitUtf16HighChar(stream, &EncodeToUtf16BE, ch)) + { + stream << Byte(ch >> 8) << Byte(ch & 0xFF); + } + } + + void EncodeToUtf32LE(std::ostream& stream, int ch) + { + stream << Byte(ch & 0xFF) << Byte((ch >> 8) & 0xFF) + << Byte((ch >> 16) & 0xFF) << Byte((ch >> 24) & 0xFF); + } + + void EncodeToUtf32BE(std::ostream& stream, int ch) + { + stream << Byte((ch >> 24) & 0xFF) << Byte((ch >> 16) & 0xFF) + << Byte((ch >> 8) & 0xFF) << Byte(ch & 0xFF); + } + + class EncodingTester + { + public: + EncodingTester(EncodingFn encoding, bool declareEncoding) + { + if (declareEncoding) + { + encoding(m_yaml, 0xFEFF); + } + + AddEntry(encoding, 0x0021, 0x007E); // Basic Latin + AddEntry(encoding, 0x00A1, 0x00FF); // Latin-1 Supplement + AddEntry(encoding, 0x0660, 0x06FF); // Arabic (largest contiguous block) + + // CJK unified ideographs (multiple lines) + AddEntry(encoding, 0x4E00, 0x4EFF); + AddEntry(encoding, 0x4F00, 0x4FFF); + AddEntry(encoding, 0x5000, 0x51FF); // 512 character line + AddEntry(encoding, 0x5200, 0x54FF); // 768 character line + AddEntry(encoding, 0x5500, 0x58FF); // 1024 character line + + AddEntry(encoding, 0x103A0, 0x103C3); // Old Persian + + m_yaml.seekg(0, std::ios::beg); + } + + std::istream& stream() {return m_yaml;} + const std::vector& entries() {return m_entries;} + + private: + std::stringstream m_yaml; + std::vector m_entries; + + void AddEntry(EncodingFn encoding, int startCh, int endCh) + { + encoding(m_yaml, '-'); + encoding(m_yaml, ' '); + encoding(m_yaml, '|'); + encoding(m_yaml, '\n'); + encoding(m_yaml, ' '); + encoding(m_yaml, ' '); + + std::stringstream entry; + for (int ch = startCh; ch <= endCh; ++ch) + { + encoding(m_yaml, ch); + EncodeToUtf8(entry, ch); + } + encoding(m_yaml, '\n'); + + m_entries.push_back(entry.str()); + } + }; + + void RunEncodingTest(EncodingFn encoding, bool declareEncoding, const std::string& name, bool& passed) + { + EncodingTester tester(encoding, declareEncoding); + std::string error; + bool ok = true; + try { + YAML::Parser parser(tester.stream()); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML::Iterator itNode = doc.begin(); + std::vector::const_iterator itEntry = tester.entries().begin(); + for (; (itNode != doc.end()) && (itEntry != tester.entries().end()); ++itNode, ++itEntry) + { + std::string stScalarValue; + if (!itNode->GetScalar(stScalarValue) && (stScalarValue == *itEntry)) + { + break; + } + } + + if ((itNode != doc.end()) || (itEntry != tester.entries().end())) + { + ok = false; + } + } catch(const YAML::Exception& e) { + ok = false; + error = e.msg; + } + if(ok) { + std::cout << "Parser test passed: " << name << "\n"; + } else { + passed = false; + std::cout << "Parser test failed: " << name << "\n"; + if(error != "") + std::cout << "Caught exception: " << error << "\n"; + } + } } bool RunParserTests() @@ -94,6 +262,17 @@ namespace Test RunParserTest(&Parser::SimpleMap, "simple map", passed); RunParserTest(&Parser::FlowSeq, "flow seq", passed); RunParserTest(&Parser::FlowMap, "flow map", passed); + + RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed); + RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed); + RunEncodingTest(&EncodeToUtf16LE, false, "UTF-16LE, no BOM", passed); + RunEncodingTest(&EncodeToUtf16LE, true, "UTF-16LE with BOM", passed); + RunEncodingTest(&EncodeToUtf16BE, false, "UTF-16BE, no BOM", passed); + RunEncodingTest(&EncodeToUtf16BE, true, "UTF-16BE with BOM", passed); + RunEncodingTest(&EncodeToUtf32LE, false, "UTF-32LE, no BOM", passed); + RunEncodingTest(&EncodeToUtf32LE, true, "UTF-32LE with BOM", passed); + RunEncodingTest(&EncodeToUtf32BE, false, "UTF-32BE, no BOM", passed); + RunEncodingTest(&EncodeToUtf32BE, true, "UTF-32BE with BOM", passed); return passed; } diff --git a/yamlcpp.vcproj b/yamlcpp.vcproj index 53d6f37..218c524 100644 --- a/yamlcpp.vcproj +++ b/yamlcpp.vcproj @@ -231,6 +231,10 @@ RelativePath=".\src\stream.cpp" > + + + + From 4ba713bf43b7d57e943870d39454ab29faaf820b Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 10 Jul 2009 03:15:08 +0000 Subject: [PATCH 107/295] Updated the visual studio project with some of the utf changes --- yamlcpp.vcproj | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/yamlcpp.vcproj b/yamlcpp.vcproj index 218c524..625f004 100644 --- a/yamlcpp.vcproj +++ b/yamlcpp.vcproj @@ -231,10 +231,6 @@ RelativePath=".\src\stream.cpp" > - - + + @@ -361,6 +361,10 @@ RelativePath=".\src\stream.h" > + + From 907960850b4ec0863b2073935e9a53feba9719dc Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 10 Jul 2009 03:20:16 +0000 Subject: [PATCH 108/295] Clarified some copy/assignment issues with the stream/streamcharsource. --- src/stream.h | 3 ++- src/streamcharsource.h | 11 ++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/stream.h b/src/stream.h index 05fb29c..697e1b9 100644 --- a/src/stream.h +++ b/src/stream.h @@ -1,5 +1,6 @@ #pragma once +#include "noncopyable.h" #include #include #include @@ -10,7 +11,7 @@ namespace YAML { static const size_t MAX_PARSER_PUSHBACK = 8; - class Stream + class Stream: private noncopyable { public: friend class StreamCharSource; diff --git a/src/streamcharsource.h b/src/streamcharsource.h index 4a1122c..d8368ac 100644 --- a/src/streamcharsource.h +++ b/src/streamcharsource.h @@ -1,5 +1,6 @@ #pragma once +#include "noncopyable.h" #include namespace YAML @@ -7,9 +8,10 @@ namespace YAML class StreamCharSource { public: - StreamCharSource(const Stream& stream); + StreamCharSource(const Stream& stream): m_offset(0), m_stream(stream) {} + StreamCharSource(const StreamCharSource& source): m_offset(source.m_offset), m_stream(source.m_stream) {} ~StreamCharSource() {} - + operator bool() const; char operator [] (std::size_t i) const { return m_stream.CharAt(m_offset + i); } bool operator !() const { return !static_cast(*this); } @@ -19,11 +21,10 @@ namespace YAML private: std::size_t m_offset; const Stream& m_stream; + + StreamCharSource& operator = (const StreamCharSource&); // non-assignable }; - inline StreamCharSource::StreamCharSource(const Stream& stream): m_offset(0), m_stream(stream) { - } - inline StreamCharSource::operator bool() const { return m_stream.ReadAheadTo(m_offset); } From 616eafc3c13bd623e5059b71210729d8c81c4cc7 Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 10 Jul 2009 03:30:04 +0000 Subject: [PATCH 109/295] Fixed warnings to compile on gcc with -Wall -pedantic -Wextra --- CMakeLists.txt | 2 +- include/emittermanip.h | 2 +- src/alias.cpp | 4 ++-- src/emitterstate.h | 2 +- src/node.cpp | 4 ++-- src/scalar.cpp | 4 ++-- src/token.h | 4 ++-- yaml-reader/main.cpp | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b1856f..4c209f8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 2.6) project (YAML_CPP) -SET(CMAKE_CXX_FLAGS "-O2") +SET(CMAKE_CXX_FLAGS "-O2 -Wall -pedantic -Wextra") enable_testing() diff --git a/include/emittermanip.h b/include/emittermanip.h index 05a9e64..22e5fd3 100644 --- a/include/emittermanip.h +++ b/include/emittermanip.h @@ -43,7 +43,7 @@ namespace YAML // Flow, // duplicate // Block, // duplicate // Auto, // duplicate - LongKey, + LongKey }; struct _Indent { diff --git a/src/alias.cpp b/src/alias.cpp index ae349cf..f6c43af 100644 --- a/src/alias.cpp +++ b/src/alias.cpp @@ -9,11 +9,11 @@ namespace YAML { } - void Alias::Parse(Scanner *pScanner, const ParserState& state) + void Alias::Parse(Scanner */*pScanner*/, const ParserState& /*state*/) { } - void Alias::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) + void Alias::Write(std::ostream& out, int /*indent*/, bool /*startedLine*/, bool /*onlyOneCharOnLine*/) { out << "\n"; } diff --git a/src/emitterstate.h b/src/emitterstate.h index 763047e..1edfa54 100644 --- a/src/emitterstate.h +++ b/src/emitterstate.h @@ -63,7 +63,7 @@ namespace YAML ES_DONE_WITH_FLOW_MAP_KEY, ES_WAITING_FOR_FLOW_MAP_VALUE, ES_WRITING_FLOW_MAP_VALUE, - ES_DONE_WITH_FLOW_MAP_VALUE, + ES_DONE_WITH_FLOW_MAP_VALUE }; class EmitterState diff --git a/src/node.cpp b/src/node.cpp index b70b4e9..34b303c 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -128,7 +128,7 @@ namespace YAML pScanner->pop(); } - void Node::ParseAnchor(Scanner *pScanner, const ParserState& state) + void Node::ParseAnchor(Scanner *pScanner, const ParserState& /*state*/) { Token& token = pScanner->peek(); if(m_anchor != "") @@ -139,7 +139,7 @@ namespace YAML pScanner->pop(); } - void Node::ParseAlias(Scanner *pScanner, const ParserState& state) + void Node::ParseAlias(Scanner *pScanner, const ParserState& /*state*/) { Token& token = pScanner->peek(); if(m_anchor != "") diff --git a/src/scalar.cpp b/src/scalar.cpp index 34e8280..5576f23 100644 --- a/src/scalar.cpp +++ b/src/scalar.cpp @@ -15,14 +15,14 @@ namespace YAML { } - void Scalar::Parse(Scanner *pScanner, const ParserState& state) + void Scalar::Parse(Scanner *pScanner, const ParserState& /*state*/) { Token& token = pScanner->peek(); m_data = token.value; pScanner->pop(); } - void Scalar::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) + void Scalar::Write(std::ostream& out, int /*indent*/, bool /*startedLine*/, bool /*onlyOneCharOnLine*/) { out << "\""; for(unsigned i=0;i Date: Fri, 10 Jul 2009 03:52:05 +0000 Subject: [PATCH 110/295] Applied patch to build and version a shared library --- CMakeLists.txt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c209f8..2edc65d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,11 @@ project (YAML_CPP) SET(CMAKE_CXX_FLAGS "-O2 -Wall -pedantic -Wextra") +set(YAML_CPP_VERSION_MAJOR "0") +set(YAML_CPP_VERSION_MINOR "1") +set(YAML_CPP_VERSION_PATCH "0") +set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}") + enable_testing() if(WIN32) @@ -25,11 +30,15 @@ file(GLOB private_headers src/*.h) file(GLOB sources src/*.cpp) include_directories(${YAML_CPP_SOURCE_DIR}/include) -add_library(yaml-cpp +add_library(yaml-cpp SHARED ${public_headers} ${private_headers} ${sources} ) +set_target_properties(yaml-cpp PROPERTIES + VERSION "${YAML_CPP_VERSION}" + SOVERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}" +) install(TARGETS yaml-cpp ${_INSTALL_DESTINATIONS}) install( From 6752e25bcd6625196e592b93c9f4d69d45d2928a Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 10 Jul 2009 04:17:30 +0000 Subject: [PATCH 111/295] (Finally) overrode Exception::what()\n --- include/exceptions.h | 6 ++++++ util/parse.cpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/exceptions.h b/include/exceptions.h index 784dc05..38e296e 100644 --- a/include/exceptions.h +++ b/include/exceptions.h @@ -2,6 +2,7 @@ #include #include +#include namespace YAML { @@ -62,6 +63,11 @@ namespace YAML Exception(int line_, int column_, const std::string& msg_) : line(line_), column(column_), msg(msg_) {} virtual ~Exception() throw() {} + virtual const char *what() const throw() { + std::stringstream output; + output << "Error at line " << line+1 << ", column " << column+1 << ": " << msg; + return output.str().c_str(); + } int line, column; std::string msg; diff --git a/util/parse.cpp b/util/parse.cpp index 1632041..12f4e6c 100644 --- a/util/parse.cpp +++ b/util/parse.cpp @@ -15,7 +15,7 @@ int main(int argc, char **argv) YAML::Node doc; parser.GetNextDocument(doc); } catch(const YAML::Exception& e) { - std::cerr << "Error at line " << e.line << ", col " << e.column << ": " << e.msg << "\n"; + std::cerr << e.what() << "\n"; } return 0; } From 10b5961f3c0dce9f4c9b5e88b3073e8ccc57f305 Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 10 Jul 2009 04:25:11 +0000 Subject: [PATCH 112/295] Set up the parse utility program to read from standard input if no file is specified --- util/parse.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/util/parse.cpp b/util/parse.cpp index 12f4e6c..8a1080d 100644 --- a/util/parse.cpp +++ b/util/parse.cpp @@ -4,16 +4,17 @@ int main(int argc, char **argv) { - if(argc != 2) { - std::cout << "Usage: " << argv[0] << " input-file\n"; - return 0; - } - - std::ifstream fin(argv[1]); + std::ifstream fin; + if(argc > 1) + fin.open(argv[1]); + + std::istream& input = (argc > 1 ? fin : std::cin); try { - YAML::Parser parser(fin); - YAML::Node doc; - parser.GetNextDocument(doc); + YAML::Parser parser(input); + while(parser) { + YAML::Node doc; + parser.GetNextDocument(doc); + } } catch(const YAML::Exception& e) { std::cerr << e.what() << "\n"; } From 689c5fa7b713b5b5add56293c485df92c8e26d05 Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 10 Jul 2009 17:26:39 +0000 Subject: [PATCH 113/295] Added check for extra compiler flags if using gcc --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2edc65d..c87584c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,9 @@ cmake_minimum_required(VERSION 2.6) project (YAML_CPP) -SET(CMAKE_CXX_FLAGS "-O2 -Wall -pedantic -Wextra") +if(CMAKE_COMPILER_IS_GNUCC) + set(CMAKE_CXX_FLAGS "-O2 -Wall -pedantic -Wextra") +endif(CMAKE_COMPILER_IS_GNUCC) set(YAML_CPP_VERSION_MAJOR "0") set(YAML_CPP_VERSION_MINOR "1") From a48191c970f8a231fe205c504f94a10f5aa6dc22 Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 10 Jul 2009 23:39:14 +0000 Subject: [PATCH 114/295] Added emitting for a YAML::Node (instead of the ad-hoc std::ostream overload) so it'll actually emit valid YAML always --- include/node.h | 7 ++- src/alias.cpp | 90 --------------------------------- src/aliascontent.cpp | 89 ++++++++++++++++++++++++++++++++ src/{alias.h => aliascontent.h} | 6 +-- src/content.h | 4 +- src/map.cpp | 28 +++------- src/map.h | 2 +- src/node.cpp | 67 +++++++----------------- src/scalar.cpp | 15 ++---- src/scalar.h | 2 +- src/sequence.cpp | 23 +++------ src/sequence.h | 2 +- util/parse.cpp | 3 ++ 13 files changed, 136 insertions(+), 202 deletions(-) delete mode 100644 src/alias.cpp create mode 100644 src/aliascontent.cpp rename src/{alias.h => aliascontent.h} (84%) diff --git a/include/node.h b/include/node.h index 1b1530f..cb4870c 100644 --- a/include/node.h +++ b/include/node.h @@ -1,7 +1,6 @@ #pragma once #include -#include #include #include #include "parserstate.h" @@ -13,6 +12,7 @@ namespace YAML { class Content; class Scanner; + class Emitter; enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP }; @@ -24,7 +24,6 @@ namespace YAML void Clear(); void Parse(Scanner *pScanner, const ParserState& state); - void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const; CONTENT_TYPE GetType() const; @@ -65,8 +64,8 @@ namespace YAML bool IsAlias() const { return m_alias; } bool IsReferenced() const { return m_referenced; } - // insertion - friend std::ostream& operator << (std::ostream& out, const Node& node); + // emitting + friend Emitter& operator << (Emitter& out, const Node& node); // ordering int Compare(const Node& rhs) const; diff --git a/src/alias.cpp b/src/alias.cpp deleted file mode 100644 index f6c43af..0000000 --- a/src/alias.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "crt.h" -#include "alias.h" -#include - -namespace YAML -{ - Alias::Alias(Content* pNodeContent) - : m_pRef(pNodeContent) - { - } - - void Alias::Parse(Scanner */*pScanner*/, const ParserState& /*state*/) - { - } - - void Alias::Write(std::ostream& out, int /*indent*/, bool /*startedLine*/, bool /*onlyOneCharOnLine*/) - { - out << "\n"; - } - - bool Alias::GetBegin(std::vector ::const_iterator& i) const - { - return m_pRef->GetBegin(i); - } - - bool Alias::GetBegin(std::map ::const_iterator& i) const - { - return m_pRef->GetBegin(i); - } - - bool Alias::GetEnd(std::vector ::const_iterator& i) const - { - return m_pRef->GetEnd(i); - } - - bool Alias::GetEnd(std::map ::const_iterator& i) const - { - return m_pRef->GetEnd(i); - } - - Node* Alias::GetNode(unsigned n) const - { - return m_pRef->GetNode(n); - } - - unsigned Alias::GetSize() const - { - return m_pRef->GetSize(); - } - - bool Alias::IsScalar() const - { - return m_pRef->IsScalar(); - } - - bool Alias::IsMap() const - { - return m_pRef->IsMap(); - } - - bool Alias::IsSequence() const - { - return m_pRef->IsSequence(); - } - - bool Alias::GetScalar(std::string& scalar) const - { - return m_pRef->GetScalar(scalar); - } - - int Alias::Compare(Content *pContent) - { - return m_pRef->Compare(pContent); - } - - int Alias::Compare(Scalar *pScalar) - { - return m_pRef->Compare(pScalar); - } - - int Alias::Compare(Sequence *pSequence) - { - return m_pRef->Compare(pSequence); - } - - int Alias::Compare(Map *pMap) - { - return m_pRef->Compare(pMap); - } -} diff --git a/src/aliascontent.cpp b/src/aliascontent.cpp new file mode 100644 index 0000000..ca64a89 --- /dev/null +++ b/src/aliascontent.cpp @@ -0,0 +1,89 @@ +#include "crt.h" +#include "aliascontent.h" + +namespace YAML +{ + AliasContent::AliasContent(Content* pNodeContent) + : m_pRef(pNodeContent) + { + } + + void AliasContent::Parse(Scanner */*pScanner*/, const ParserState& /*state*/) + { + } + + void AliasContent::Write(Emitter&) const + { + // no content (just an alias) + } + + bool AliasContent::GetBegin(std::vector ::const_iterator& i) const + { + return m_pRef->GetBegin(i); + } + + bool AliasContent::GetBegin(std::map ::const_iterator& i) const + { + return m_pRef->GetBegin(i); + } + + bool AliasContent::GetEnd(std::vector ::const_iterator& i) const + { + return m_pRef->GetEnd(i); + } + + bool AliasContent::GetEnd(std::map ::const_iterator& i) const + { + return m_pRef->GetEnd(i); + } + + Node* AliasContent::GetNode(unsigned n) const + { + return m_pRef->GetNode(n); + } + + unsigned AliasContent::GetSize() const + { + return m_pRef->GetSize(); + } + + bool AliasContent::IsScalar() const + { + return m_pRef->IsScalar(); + } + + bool AliasContent::IsMap() const + { + return m_pRef->IsMap(); + } + + bool AliasContent::IsSequence() const + { + return m_pRef->IsSequence(); + } + + bool AliasContent::GetScalar(std::string& scalar) const + { + return m_pRef->GetScalar(scalar); + } + + int AliasContent::Compare(Content *pContent) + { + return m_pRef->Compare(pContent); + } + + int AliasContent::Compare(Scalar *pScalar) + { + return m_pRef->Compare(pScalar); + } + + int AliasContent::Compare(Sequence *pSequence) + { + return m_pRef->Compare(pSequence); + } + + int AliasContent::Compare(Map *pMap) + { + return m_pRef->Compare(pMap); + } +} diff --git a/src/alias.h b/src/aliascontent.h similarity index 84% rename from src/alias.h rename to src/aliascontent.h index 9513665..55460d7 100644 --- a/src/alias.h +++ b/src/aliascontent.h @@ -4,13 +4,13 @@ namespace YAML { - class Alias : public Content + class AliasContent : public Content { public: - Alias(Content *pNodeContent); + AliasContent(Content *pNodeContent); virtual void Parse(Scanner* pScanner, const ParserState& state); - virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); + virtual void Write(Emitter&) const; virtual bool GetBegin(std::vector ::const_iterator&) const; virtual bool GetBegin(std::map ::const_iterator&) const; diff --git a/src/content.h b/src/content.h index 6399682..5bb7ffa 100644 --- a/src/content.h +++ b/src/content.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include #include "parserstate.h" @@ -15,6 +14,7 @@ namespace YAML class Scalar; class Sequence; class Map; + class Emitter; class Content { @@ -23,7 +23,7 @@ namespace YAML virtual ~Content(); virtual void Parse(Scanner *pScanner, const ParserState& state) = 0; - virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) = 0; + virtual void Write(Emitter& out) const = 0; virtual bool GetBegin(std::vector ::const_iterator&) const { return false; } virtual bool GetBegin(std::map ::const_iterator&) const { return false; } diff --git a/src/map.cpp b/src/map.cpp index b7a7ec8..3565b70 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -4,7 +4,7 @@ #include "scanner.h" #include "token.h" #include "exceptions.h" -#include +#include "emitter.h" #include namespace YAML @@ -129,28 +129,12 @@ namespace YAML } } - void Map::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) + void Map::Write(Emitter& out) const { - if(startedLine && !onlyOneCharOnLine) - out << "\n"; - - for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) { - if((startedLine && !onlyOneCharOnLine) || it != m_data.begin()) { - for(int i=0;ifirst->Write(out, indent + 1, true, it!= m_data.begin() || !startedLine || onlyOneCharOnLine); - - for(int i=0;isecond->Write(out, indent + 1, true, true); - } - - if(m_data.empty()) - out << "\n"; + 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; } int Map::Compare(Content *pContent) diff --git a/src/map.h b/src/map.h index be722f4..71da430 100644 --- a/src/map.h +++ b/src/map.h @@ -17,7 +17,7 @@ namespace YAML virtual bool GetBegin(std::map ::const_iterator& it) const; virtual bool GetEnd(std::map ::const_iterator& it) const; virtual void Parse(Scanner *pScanner, const ParserState& state); - virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine); + virtual void Write(Emitter& out) const; virtual bool IsMap() const { return true; } diff --git a/src/node.cpp b/src/node.cpp index 34b303c..89341cc 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -7,9 +7,9 @@ #include "scalar.h" #include "sequence.h" #include "map.h" -#include "alias.h" +#include "aliascontent.h" #include "iterpriv.h" -#include +#include "emitter.h" namespace YAML { @@ -66,7 +66,7 @@ namespace YAML // being deleted twice Content *pAliasedContent = pReferencedNode->m_pContent; if(pAliasedContent) - m_pContent = new Alias(pAliasedContent); + m_pContent = new AliasContent(pAliasedContent); return; } @@ -152,50 +152,6 @@ namespace YAML pScanner->pop(); } - void Node::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const - { - // If using an anchor or tag for the whole document, document start - // must be explicit - bool indicateDocStart = (indent == 0); - - // write anchor/alias - if(m_anchor != "") { - if (indicateDocStart) { - out << "--- "; - indicateDocStart = false; - } - - if(m_alias) - out << "*"; - else - out << "&"; - out << m_anchor << " "; - startedLine = true; - onlyOneCharOnLine = false; - } - - // write tag - if(m_tag != "") { - if (indicateDocStart) { - out << "--- "; - indicateDocStart = false; - } - - // put the tag in the "proper" brackets - if(m_tag.substr(0, 2) == std::string("!<") && m_tag.substr(m_tag.size() - 1) == std::string(">")) - out << m_tag << " "; - else - out << "!<" << m_tag << "> "; - startedLine = true; - onlyOneCharOnLine = false; - } - - if(!m_pContent) - out << "\n"; - else - m_pContent->Write(out, indent, startedLine, onlyOneCharOnLine); - } - CONTENT_TYPE Node::GetType() const { if(!m_pContent) @@ -289,9 +245,22 @@ namespace YAML return m_pContent->GetScalar(s); } - std::ostream& operator << (std::ostream& out, const Node& node) + Emitter& operator << (Emitter& out, const Node& node) { - node.Write(out, 0, false, false); + // write anchor/alias + if(node.m_anchor != "") { + if(node.m_alias) + out << Alias(node.m_anchor); + else + out << Anchor(node.m_anchor); + } + + // TODO: write tag + + // write content + if(node.m_pContent) + node.m_pContent->Write(out); + return out; } diff --git a/src/scalar.cpp b/src/scalar.cpp index 5576f23..e8146fa 100644 --- a/src/scalar.cpp +++ b/src/scalar.cpp @@ -4,6 +4,7 @@ #include "token.h" #include "exceptions.h" #include "node.h" +#include "emitter.h" namespace YAML { @@ -22,19 +23,9 @@ namespace YAML pScanner->pop(); } - void Scalar::Write(std::ostream& out, int /*indent*/, bool /*startedLine*/, bool /*onlyOneCharOnLine*/) + void Scalar::Write(Emitter& out) const { - out << "\""; - for(unsigned i=0;i +#include "emitter.h" namespace YAML { @@ -133,23 +133,12 @@ namespace YAML } } - void Sequence::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) + void Sequence::Write(Emitter& out) const { - if(startedLine && !onlyOneCharOnLine) - out << "\n"; - - for(unsigned i=0;i 0) { - for(int j=0;jWrite(out, indent + 1, true, i > 0 || !startedLine || onlyOneCharOnLine); - } - - if(m_data.empty()) - out << "\n"; + out << BeginSeq; + for(unsigned i=0;i Date: Sun, 12 Jul 2009 02:59:23 +0000 Subject: [PATCH 115/295] Added FindValue to more easily read optional keys in a map --- include/node.h | 67 +++++++++------------------------------------- include/nodeimpl.h | 65 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 54 deletions(-) create mode 100644 include/nodeimpl.h diff --git a/include/node.h b/include/node.h index cb4870c..fd54c13 100644 --- a/include/node.h +++ b/include/node.h @@ -7,6 +7,8 @@ #include "exceptions.h" #include "iterator.h" #include "conversion.h" +#include "noncopyable.h" +#include namespace YAML { @@ -16,7 +18,7 @@ namespace YAML enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP }; - class Node + class Node: private noncopyable { public: Node(); @@ -48,11 +50,11 @@ namespace YAML // just for maps template - const Node& GetValue(const T& key) const; - + const Node *FindValue(const T& key) const; + const Node *FindValue(const char *key) const; + template const Node& operator [] (const T& key) const; - const Node& operator [] (const char *key) const; // just for sequences @@ -72,11 +74,11 @@ namespace YAML friend bool operator < (const Node& n1, const Node& n2); private: - // shouldn't be copyable! (at least for now) - Node(const Node& rhs); - Node& operator = (const Node& rhs); - - private: + // helper for maps + template + const Node& GetValue(const T& key) const; + + // helpers for parsing void ParseHeader(Scanner *pScanner, const ParserState& state); void ParseTag(Scanner *pScanner, const ParserState& state); void ParseAnchor(Scanner *pScanner, const ParserState& state); @@ -90,49 +92,6 @@ namespace YAML const Node *m_pIdentity; mutable bool m_referenced; }; - - // templated things we need to keep inline in the header - template - inline bool Node::Read(T& value) const { - std::string scalar; - if(!GetScalar(scalar)) - return false; - - return Convert(scalar, value); - } - - template - inline void operator >> (const Node& node, T& value) - { - if(!node.Read(value)) - throw InvalidScalar(node.m_line, node.m_column); - } - - template - inline const Node& Node::GetValue(const T& key) const - { - if(!m_pContent) - throw BadDereference(); - - for(Iterator it=begin();it!=end();++it) { - T t; - if(it.first().Read(t)) { - if(key == t) - return it.second(); - } - } - - throw MakeTypedKeyNotFound(m_line, m_column, key); - } - - template - inline const Node& Node::operator [] (const T& key) const - { - return GetValue(key); - } - - inline const Node& Node::operator [] (const char *key) const - { - return GetValue(std::string(key)); - } } + +#include "nodeimpl.h" diff --git a/include/nodeimpl.h b/include/nodeimpl.h new file mode 100644 index 0000000..9bfc2d7 --- /dev/null +++ b/include/nodeimpl.h @@ -0,0 +1,65 @@ +#pragma once + +namespace YAML +{ + // implementation of templated things + template + inline bool Node::Read(T& value) const { + std::string scalar; + if(!GetScalar(scalar)) + return false; + + return Convert(scalar, value); + } + + template + inline void operator >> (const Node& node, T& value) { + if(!node.Read(value)) + throw InvalidScalar(node.m_line, node.m_column); + } + + template + inline const Node *Node::FindValue(const T& key) const { + if(!m_pContent) + return 0; + + for(Iterator it=begin();it!=end();++it) { + T t; + if(it.first().Read(t)) { + if(key == t) + return &it.second(); + } + } + + return 0; + } + + inline const Node *Node::FindValue(const char *key) const { + return FindValue(std::string(key)); + } + + template + inline const Node& Node::GetValue(const T& key) const { + if(!m_pContent) + throw BadDereference(); + + for(Iterator it=begin();it!=end();++it) { + T t; + if(it.first().Read(t)) { + if(key == t) + return it.second(); + } + } + + throw MakeTypedKeyNotFound(m_line, m_column, key); + } + + template + inline const Node& Node::operator [] (const T& key) const { + return GetValue(key); + } + + inline const Node& Node::operator [] (const char *key) const { + return GetValue(std::string(key)); + } +} From 64a5687656481c8b52d7cb49d260b5fe024a65fb Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 15 Jul 2009 20:37:11 +0000 Subject: [PATCH 116/295] Added support for pkgconfig --- CMakeLists.txt | 13 ++++++++++--- yaml-cpp.pc.cmake | 11 +++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 yaml-cpp.pc.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index c87584c..2536508 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,15 +18,17 @@ if(WIN32) else(WIN32) set(_library_dir lib) endif(WIN32) + +set(INCLUDE_INSTALL_DIR include/yaml-cpp) +set(LIB_INSTALL_DIR ${_library_dir}${LIB_SUFFIX}) + # set(_INSTALL_DESTINATIONS RUNTIME DESTINATION bin - LIBRARY DESTINATION ${_library_dir}${LIB_SUFFIX} + LIBRARY DESTINATION ${LIB_INSTALL_DIR} ARCHIVE DESTINATION lib${LIB_SUFFIX} ) # -set(INCLUDE_INSTALL_DIR include/yaml-cpp) - file(GLOB public_headers include/*.h) file(GLOB private_headers src/*.h) file(GLOB sources src/*.cpp) @@ -48,5 +50,10 @@ install( DESTINATION ${INCLUDE_INSTALL_DIR} ) +if(UNIX) + configure_file("yaml-cpp.pc.cmake" yaml-cpp.pc @ONLY) + install(FILES yaml-cpp.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) +endif(UNIX) + add_subdirectory (yaml-reader) add_subdirectory (util) diff --git a/yaml-cpp.pc.cmake b/yaml-cpp.pc.cmake new file mode 100644 index 0000000..3f69f52 --- /dev/null +++ b/yaml-cpp.pc.cmake @@ -0,0 +1,11 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=@LIB_INSTALL_DIR@ +includedir=@INCLUDE_INSTALL_DIR@ + +Name: Yaml-cpp +Description: A YAML parser for C++ +Version: @YAML_CPP_VERSION@ +Requires: +Libs: -L${libdir} -lyaml-cpp +Cflags: -I${includedir} From fd5bf7c29ab2831ef512e4ac72ab0c41e6f3d84b Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 15 Jul 2009 20:38:25 +0000 Subject: [PATCH 117/295] Cosmetic change to .pc.cmake file --- yaml-cpp.pc.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yaml-cpp.pc.cmake b/yaml-cpp.pc.cmake index 3f69f52..58e25af 100644 --- a/yaml-cpp.pc.cmake +++ b/yaml-cpp.pc.cmake @@ -4,7 +4,7 @@ libdir=@LIB_INSTALL_DIR@ includedir=@INCLUDE_INSTALL_DIR@ Name: Yaml-cpp -Description: A YAML parser for C++ +Description: A YAML parser and emitter for C++ Version: @YAML_CPP_VERSION@ Requires: Libs: -L${libdir} -lyaml-cpp From f8440aa0e59925fdfcfd4d9708ac23f3562404c3 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 15 Jul 2009 20:47:51 +0000 Subject: [PATCH 118/295] Patched to read into std::wstring --- include/conversion.h | 3 +++ src/conversion.cpp | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/include/conversion.h b/include/conversion.h index 208a1ef..8c06191 100644 --- a/include/conversion.h +++ b/include/conversion.h @@ -32,4 +32,7 @@ namespace YAML template <> bool Converter::Convert(const std::string& input, bool& output); + + template <> + bool Converter::Convert(const std::string& input, std::wstring& output); } diff --git a/src/conversion.cpp b/src/conversion.cpp index 0b34501..7a55e1c 100644 --- a/src/conversion.cpp +++ b/src/conversion.cpp @@ -1,6 +1,6 @@ #include "conversion.h" #include - +#include //////////////////////////////////////////////////////////////// // Specializations for converting a string to specific types @@ -82,5 +82,19 @@ namespace YAML return false; } + + template <> + bool Converter::Convert(const std::string& input, std::wstring& output) + { + output.clear(); + output.resize(std::mbstowcs(NULL, input.data(), input.size())); + std::mbstowcs( + (wchar_t *) output.data(), + input.data(), + input.size() + ); + + return true; + } } From e6a26ef10426fab8722ed9a21958f5bb4dd70483 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 20 Jul 2009 20:18:59 +0000 Subject: [PATCH 119/295] Updated visual studio project, and fixed a VS warning --- src/aliascontent.cpp | 2 +- yamlcpp.vcproj | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/aliascontent.cpp b/src/aliascontent.cpp index ca64a89..9f98571 100644 --- a/src/aliascontent.cpp +++ b/src/aliascontent.cpp @@ -8,7 +8,7 @@ namespace YAML { } - void AliasContent::Parse(Scanner */*pScanner*/, const ParserState& /*state*/) + void AliasContent::Parse(Scanner * /*pScanner*/, const ParserState& /*state*/) { } diff --git a/yamlcpp.vcproj b/yamlcpp.vcproj index 625f004..749ac8e 100644 --- a/yamlcpp.vcproj +++ b/yamlcpp.vcproj @@ -168,7 +168,7 @@ Name="Representation" > Date: Fri, 24 Jul 2009 06:18:46 +0000 Subject: [PATCH 120/295] Fixed location of yaml-cpp.pc file --- CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2536508..e71963d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,8 +51,9 @@ install( ) if(UNIX) - configure_file("yaml-cpp.pc.cmake" yaml-cpp.pc @ONLY) - install(FILES yaml-cpp.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) + set(PC_FILE ${CMAKE_BINARY_DIR}/yaml-cpp.pc) + configure_file("yaml-cpp.pc.cmake" ${PC_FILE} @ONLY) + install(FILES ${PC_FILE} DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) endif(UNIX) add_subdirectory (yaml-reader) From ab7c8b0df0a87adee03f6133a283bbfbc933a316 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sat, 25 Jul 2009 18:03:58 +0000 Subject: [PATCH 121/295] Fixed yaml-cpp.pc file (with prefix) --- yaml-cpp.pc.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yaml-cpp.pc.cmake b/yaml-cpp.pc.cmake index 58e25af..cf4b3d0 100644 --- a/yaml-cpp.pc.cmake +++ b/yaml-cpp.pc.cmake @@ -1,7 +1,7 @@ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@CMAKE_INSTALL_PREFIX@ -libdir=@LIB_INSTALL_DIR@ -includedir=@INCLUDE_INSTALL_DIR@ +libdir=${prefix}/@LIB_INSTALL_DIR@ +includedir=${prefix}/@INCLUDE_INSTALL_DIR@ Name: Yaml-cpp Description: A YAML parser and emitter for C++ From 27055f178faf91def80f6d826c0efa4344e04096 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sat, 25 Jul 2009 18:58:41 +0000 Subject: [PATCH 122/295] Fixed bug with simple keys that are quoted scalars --- src/scantoken.cpp | 9 +- yaml-reader/parsertests.cpp | 473 +++++++++++++++++++----------------- yaml-reader/tests.cpp | 1 + yaml-reader/tests.h | 1 + 4 files changed, 260 insertions(+), 224 deletions(-) diff --git a/src/scantoken.cpp b/src/scantoken.cpp index 4735a1a..bb8373a 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -309,8 +309,8 @@ namespace YAML { std::string scalar; - // eat single or double quote - char quote = INPUT.get(); + // peek at single or double quote (don't eat because we need to preserve (for the time being) the input position) + char quote = INPUT.peek(); bool single = (quote == '\''); // setup the scanning parameters @@ -330,6 +330,11 @@ namespace YAML InsertSimpleKey(); int line = INPUT.line, column = INPUT.column; + + // now eat that opening quote + INPUT.get(); + + // and scan scalar = ScanScalar(INPUT, params); m_simpleKeyAllowed = false; diff --git a/yaml-reader/parsertests.cpp b/yaml-reader/parsertests.cpp index 2c45eb4..b78cc53 100644 --- a/yaml-reader/parsertests.cpp +++ b/yaml-reader/parsertests.cpp @@ -1,222 +1,251 @@ -#include "tests.h" -#include "yaml.h" -#include - -namespace Test -{ - namespace Parser { - void SimpleScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = "Hello, World!"; - desiredOutput = "Hello, World!"; - } - - void MultiLineScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = - "normal scalar, but\n" - "over several lines"; - desiredOutput = "normal scalar, but over several lines"; - } - - void LiteralScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = - "|\n" - " literal scalar - so we can draw ASCII:\n" - " \n" - " - -\n" - " | - |\n" - " -----\n"; - desiredOutput = - "literal scalar - so we can draw ASCII:\n" - "\n" - " - -\n" - " | - |\n" - " -----\n"; - } - - void FoldedScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = - ">\n" - " and a folded scalar... so we\n" - " can just keep writing various\n" - " things. And if we want to keep indentation:\n" - " \n" - " we just indent a little\n" - " see, this stays indented"; - desiredOutput = - "and a folded scalar... so we" - " can just keep writing various" - " things. And if we want to keep indentation:\n" - "\n" - " we just indent a little\n" - " see, this stays indented"; - } - - void ChompedFoldedScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = - ">-\n" - " Here's a folded scalar\n" - " that gets chomped."; - desiredOutput = - "Here's a folded scalar" - " that gets chomped."; - } - - void ChompedLiteralScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = - "|-\n" - " Here's a literal scalar\n" - " that gets chomped."; - desiredOutput = - "Here's a literal scalar\n" - "that gets chomped."; - } - - void FoldedScalarWithIndent(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = - ">2\n" - " Here's a folded scalar\n" - " that starts with some indentation."; - desiredOutput = - " Here's a folded scalar\n" - "that starts with some indentation."; - } - - void ColonScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = "::vector"; - desiredOutput = "::vector"; - } - - void QuotedScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = "\": - ()\""; - desiredOutput = ": - ()"; - } - - void CommaScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = "Up, up, and away!"; - desiredOutput = "Up, up, and away!"; - } - - void DashScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = "-123"; - desiredOutput = "-123"; - } - - void URLScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = "http://example.com/foo#bar"; - desiredOutput = "http://example.com/foo#bar"; - } - - bool SimpleSeq() - { - std::string input = - "- eggs\n" - "- bread\n" - "- milk"; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - std::string output; - doc[0] >> output; - if(output != "eggs") - return false; - doc[1] >> output; - if(output != "bread") - return false; - doc[2] >> output; - if(output != "milk") - return false; - - return true; - } - - bool SimpleMap() - { - std::string input = - "name: Prince Fielder\n" - "position: 1B\n" - "bats: L"; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - std::string output; - doc["name"] >> output; - if(output != "Prince Fielder") - return false; - doc["position"] >> output; - if(output != "1B") - return false; - doc["bats"] >> output; - if(output != "L") - return false; - - return true; - } - - bool FlowSeq() - { - std::string input = "[ 2 , 3, 5 , 7, 11]"; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - int output; - doc[0] >> output; - if(output != 2) - return false; - doc[1] >> output; - if(output != 3) - return false; - doc[2] >> output; - if(output != 5) - return false; - doc[3] >> output; - if(output != 7) - return false; - doc[4] >> output; - if(output != 11) - return false; - - return true; - } - - bool FlowMap() - { - std::string input = "{hr: 65, avg: 0.278}"; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - std::string output; - doc["hr"] >> output; - if(output != "65") - return false; - doc["avg"] >> output; - if(output != "0.278") - return false; - - return true; - } - } -} +#include "tests.h" +#include "yaml.h" +#include +#include + +namespace Test +{ + namespace Parser { + void SimpleScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = "Hello, World!"; + desiredOutput = "Hello, World!"; + } + + void MultiLineScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = + "normal scalar, but\n" + "over several lines"; + desiredOutput = "normal scalar, but over several lines"; + } + + void LiteralScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = + "|\n" + " literal scalar - so we can draw ASCII:\n" + " \n" + " - -\n" + " | - |\n" + " -----\n"; + desiredOutput = + "literal scalar - so we can draw ASCII:\n" + "\n" + " - -\n" + " | - |\n" + " -----\n"; + } + + void FoldedScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = + ">\n" + " and a folded scalar... so we\n" + " can just keep writing various\n" + " things. And if we want to keep indentation:\n" + " \n" + " we just indent a little\n" + " see, this stays indented"; + desiredOutput = + "and a folded scalar... so we" + " can just keep writing various" + " things. And if we want to keep indentation:\n" + "\n" + " we just indent a little\n" + " see, this stays indented"; + } + + void ChompedFoldedScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = + ">-\n" + " Here's a folded scalar\n" + " that gets chomped."; + desiredOutput = + "Here's a folded scalar" + " that gets chomped."; + } + + void ChompedLiteralScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = + "|-\n" + " Here's a literal scalar\n" + " that gets chomped."; + desiredOutput = + "Here's a literal scalar\n" + "that gets chomped."; + } + + void FoldedScalarWithIndent(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = + ">2\n" + " Here's a folded scalar\n" + " that starts with some indentation."; + desiredOutput = + " Here's a folded scalar\n" + "that starts with some indentation."; + } + + void ColonScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = "::vector"; + desiredOutput = "::vector"; + } + + void QuotedScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = "\": - ()\""; + desiredOutput = ": - ()"; + } + + void CommaScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = "Up, up, and away!"; + desiredOutput = "Up, up, and away!"; + } + + void DashScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = "-123"; + desiredOutput = "-123"; + } + + void URLScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = "http://example.com/foo#bar"; + desiredOutput = "http://example.com/foo#bar"; + } + + bool SimpleSeq() + { + std::string input = + "- eggs\n" + "- bread\n" + "- milk"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc[0] >> output; + if(output != "eggs") + return false; + doc[1] >> output; + if(output != "bread") + return false; + doc[2] >> output; + if(output != "milk") + return false; + + return true; + } + + bool SimpleMap() + { + std::string input = + "name: Prince Fielder\n" + "position: 1B\n" + "bats: L"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc["name"] >> output; + if(output != "Prince Fielder") + return false; + doc["position"] >> output; + if(output != "1B") + return false; + doc["bats"] >> output; + if(output != "L") + return false; + + return true; + } + + bool FlowSeq() + { + std::string input = "[ 2 , 3, 5 , 7, 11]"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + int output; + doc[0] >> output; + if(output != 2) + return false; + doc[1] >> output; + if(output != 3) + return false; + doc[2] >> output; + if(output != 5) + return false; + doc[3] >> output; + if(output != 7) + return false; + doc[4] >> output; + if(output != 11) + return false; + + return true; + } + + bool FlowMap() + { + std::string input = "{hr: 65, avg: 0.278}"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc["hr"] >> output; + if(output != "65") + return false; + doc["avg"] >> output; + if(output != "0.278") + return false; + + return true; + } + + bool QuotedSimpleKeys() + { + std::string KeyValue[3] = { "\"double\": double\n", "'single': single\n", "plain: plain\n" }; + + int perm[3] = { 0, 1, 2 }; + do { + std::string input = KeyValue[perm[0]] + KeyValue[perm[1]] + KeyValue[perm[2]]; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc["double"] >> output; + if(output != "double") + return false; + doc["single"] >> output; + if(output != "single") + return false; + doc["plain"] >> output; + if(output != "plain") + return false; + } while(std::next_permutation(perm, perm + 3)); + + return true; + } + } +} diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp index c4d222e..a499cb3 100644 --- a/yaml-reader/tests.cpp +++ b/yaml-reader/tests.cpp @@ -262,6 +262,7 @@ namespace Test RunParserTest(&Parser::SimpleMap, "simple map", passed); RunParserTest(&Parser::FlowSeq, "flow seq", passed); RunParserTest(&Parser::FlowMap, "flow map", passed); + RunParserTest(&Parser::QuotedSimpleKeys, "quoted simple keys", passed); RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed); RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed); diff --git a/yaml-reader/tests.h b/yaml-reader/tests.h index fb33c24..20ec4d3 100644 --- a/yaml-reader/tests.h +++ b/yaml-reader/tests.h @@ -28,6 +28,7 @@ namespace Test { bool SimpleMap(); bool FlowSeq(); bool FlowMap(); + bool QuotedSimpleKeys(); } namespace Emitter { From d0870b41129cea49c110c3bc5a077ca57a842413 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sun, 26 Jul 2009 01:37:21 +0000 Subject: [PATCH 123/295] Fixed the Exception::what() function --- include/exceptions.h | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/include/exceptions.h b/include/exceptions.h index 38e296e..2df88b6 100644 --- a/include/exceptions.h +++ b/include/exceptions.h @@ -61,16 +61,19 @@ namespace YAML class Exception: public std::exception { public: Exception(int line_, int column_, const std::string& msg_) - : line(line_), column(column_), msg(msg_) {} + : line(line_), column(column_), msg(msg_) { + std::stringstream output; + output << "Error at line " << line+1 << ", column " << column+1 << ": " << msg; + what_ = output.str(); + } virtual ~Exception() throw() {} - virtual const char *what() const throw() { - std::stringstream output; - output << "Error at line " << line+1 << ", column " << column+1 << ": " << msg; - return output.str().c_str(); - } + virtual const char *what() const throw() { return what_.c_str(); } int line, column; std::string msg; + + private: + std::string what_; }; class ParserException: public Exception { From c4e1446dffb32fde3c4eaee46b280a80824c1906 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sun, 26 Jul 2009 07:42:50 +0000 Subject: [PATCH 124/295] Fixed bug in emitting null nodes --- src/node.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/node.cpp b/src/node.cpp index 89341cc..f41af12 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -260,6 +260,8 @@ namespace YAML // write content if(node.m_pContent) node.m_pContent->Write(out); + else + out << ""; return out; } From 25b5e9fec1c28d94a4a05dd1825c1e0e3b171d6c Mon Sep 17 00:00:00 2001 From: jbeder Date: Sun, 26 Jul 2009 07:57:22 +0000 Subject: [PATCH 125/295] Fixed hex output in emitter (should be always two hex chars) --- src/emitterutils.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index 2fc6ad7..907e78c 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -2,8 +2,9 @@ #include "exp.h" #include "indentation.h" #include "exceptions.h" -#include #include "stringsource.h" +#include +#include namespace YAML { @@ -82,7 +83,7 @@ namespace YAML } else { // TODO: for the common escaped characters, give their usual symbol std::stringstream str; - str << "\\x" << std::hex << static_cast (ch); + str << "\\x" << std::hex << std::setfill('0') << std::setw(2) << static_cast (ch); out << str.str(); } } From 7e26c711cf2329e42e29624bb95eef70ef6780c2 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 27 Jul 2009 02:56:18 +0000 Subject: [PATCH 126/295] Collected pos, line, and column into a Mark struct --- include/exceptions.h | 37 ++++++++-------- include/node.h | 18 ++++---- include/nodeimpl.h | 4 +- src/exp.cpp | 10 ++--- src/map.cpp | 10 ++--- src/node.cpp | 11 +++-- src/parser.cpp | 8 ++-- src/scanner.cpp | 27 ++++++------ src/scanner.h | 7 +-- src/scanscalar.cpp | 20 ++++----- src/scantoken.cpp | 82 ++++++++++++++++++------------------ src/sequence.cpp | 8 ++-- src/simplekey.cpp | 12 +++--- src/stream.cpp | 10 ++--- src/stream.h | 11 ++++- src/token.h | 5 ++- yaml-reader/emittertests.cpp | 2 +- 17 files changed, 145 insertions(+), 137 deletions(-) diff --git a/include/exceptions.h b/include/exceptions.h index 2df88b6..b70c82a 100644 --- a/include/exceptions.h +++ b/include/exceptions.h @@ -1,5 +1,6 @@ #pragma once +#include "mark.h" #include #include #include @@ -60,16 +61,16 @@ namespace YAML class Exception: public std::exception { public: - Exception(int line_, int column_, const std::string& msg_) - : line(line_), column(column_), msg(msg_) { + Exception(const Mark& mark_, const std::string& msg_) + : mark(mark_), msg(msg_) { std::stringstream output; - output << "Error at line " << line+1 << ", column " << column+1 << ": " << msg; + output << "Error at line " << mark.line+1 << ", column " << mark.column+1 << ": " << msg; what_ = output.str(); } virtual ~Exception() throw() {} virtual const char *what() const throw() { return what_.c_str(); } - int line, column; + Mark mark; std::string msg; private: @@ -78,53 +79,53 @@ namespace YAML class ParserException: public Exception { public: - ParserException(int line_, int column_, const std::string& msg_) - : Exception(line_, column_, msg_) {} + ParserException(const Mark& mark_, const std::string& msg_) + : Exception(mark_, msg_) {} }; class RepresentationException: public Exception { public: - RepresentationException(int line_, int column_, const std::string& msg_) - : Exception(line_, column_, msg_) {} + RepresentationException(const Mark& mark_, const std::string& msg_) + : Exception(mark_, msg_) {} }; // representation exceptions class InvalidScalar: public RepresentationException { public: - InvalidScalar(int line_, int column_) - : RepresentationException(line_, column_, ErrorMsg::INVALID_SCALAR) {} + InvalidScalar(const Mark& mark_) + : RepresentationException(mark_, ErrorMsg::INVALID_SCALAR) {} }; class KeyNotFound: public RepresentationException { public: - KeyNotFound(int line_, int column_) - : RepresentationException(line_, column_, ErrorMsg::KEY_NOT_FOUND) {} + KeyNotFound(const Mark& mark_) + : RepresentationException(mark_, ErrorMsg::KEY_NOT_FOUND) {} }; template class TypedKeyNotFound: public KeyNotFound { public: - TypedKeyNotFound(int line_, int column_, const T& key_) - : KeyNotFound(line_, column_), key(key_) {} + TypedKeyNotFound(const Mark& mark_, const T& key_) + : KeyNotFound(mark_), key(key_) {} ~TypedKeyNotFound() throw() {} T key; }; template - TypedKeyNotFound MakeTypedKeyNotFound(int line, int column, const T& key) { - return TypedKeyNotFound (line, column, key); + TypedKeyNotFound MakeTypedKeyNotFound(const Mark& mark, const T& key) { + return TypedKeyNotFound (mark, key); } class BadDereference: public RepresentationException { public: BadDereference() - : RepresentationException(-1, -1, ErrorMsg::BAD_DEREFERENCE) {} + : RepresentationException(Mark::null(), ErrorMsg::BAD_DEREFERENCE) {} }; class EmitterException: public Exception { public: EmitterException(const std::string& msg_) - : Exception(-1, -1, msg_) {} + : Exception(Mark::null(), msg_) {} }; } diff --git a/include/node.h b/include/node.h index fd54c13..3ae77c3 100644 --- a/include/node.h +++ b/include/node.h @@ -1,14 +1,15 @@ #pragma once +#include "conversion.h" +#include "exceptions.h" +#include "iterator.h" +#include "mark.h" +#include "noncopyable.h" +#include "parserstate.h" +#include #include #include #include -#include "parserstate.h" -#include "exceptions.h" -#include "iterator.h" -#include "conversion.h" -#include "noncopyable.h" -#include namespace YAML { @@ -30,8 +31,7 @@ namespace YAML CONTENT_TYPE GetType() const; // file location of start of this node - int GetLine() const { return m_line; } - int GetColumn() const { return m_column; } + const Mark GetMark() const { return m_mark; } // accessors Iterator begin() const; @@ -85,7 +85,7 @@ namespace YAML void ParseAlias(Scanner *pScanner, const ParserState& state); private: - int m_line, m_column; + Mark m_mark; std::string m_anchor, m_tag; Content *m_pContent; bool m_alias; diff --git a/include/nodeimpl.h b/include/nodeimpl.h index 9bfc2d7..268176f 100644 --- a/include/nodeimpl.h +++ b/include/nodeimpl.h @@ -15,7 +15,7 @@ namespace YAML template inline void operator >> (const Node& node, T& value) { if(!node.Read(value)) - throw InvalidScalar(node.m_line, node.m_column); + throw InvalidScalar(node.m_mark); } template @@ -51,7 +51,7 @@ namespace YAML } } - throw MakeTypedKeyNotFound(m_line, m_column, key); + throw MakeTypedKeyNotFound(m_mark, key); } template diff --git a/src/exp.cpp b/src/exp.cpp index 7148acc..028b7d7 100644 --- a/src/exp.cpp +++ b/src/exp.cpp @@ -7,7 +7,7 @@ namespace YAML { namespace Exp { - unsigned ParseHex(const std::string& str, int line, int column) + unsigned ParseHex(const std::string& str, const Mark& mark) { unsigned value = 0; for(unsigned i=0;i= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) { std::stringstream msg; msg << ErrorMsg::INVALID_UNICODE << value; - throw ParserException(in.line, in.column, msg.str()); + throw ParserException(in.mark(), msg.str()); } // now break it up into chars @@ -107,7 +107,7 @@ namespace YAML } std::stringstream msg; - throw ParserException(in.line, in.column, ErrorMsg::INVALID_ESCAPE + ch); + throw ParserException(in.mark(), ErrorMsg::INVALID_ESCAPE + ch); } } } diff --git a/src/map.cpp b/src/map.cpp index 3565b70..46a6977 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -58,11 +58,11 @@ namespace YAML while(1) { if(pScanner->empty()) - throw ParserException(-1, -1, ErrorMsg::END_OF_MAP); + throw ParserException(Mark::null(), ErrorMsg::END_OF_MAP); Token token = pScanner->peek(); if(token.type != TT_KEY && token.type != TT_BLOCK_END) - throw ParserException(token.line, token.column, ErrorMsg::END_OF_MAP); + throw ParserException(token.mark, ErrorMsg::END_OF_MAP); pScanner->pop(); if(token.type == TT_BLOCK_END) @@ -91,7 +91,7 @@ namespace YAML while(1) { if(pScanner->empty()) - throw ParserException(-1, -1, ErrorMsg::END_OF_MAP_FLOW); + throw ParserException(Mark::null(), ErrorMsg::END_OF_MAP_FLOW); Token& token = pScanner->peek(); // first check for end @@ -102,7 +102,7 @@ namespace YAML // now it better be a key if(token.type != TT_KEY) - throw ParserException(token.line, token.column, ErrorMsg::END_OF_MAP_FLOW); + throw ParserException(token.mark, ErrorMsg::END_OF_MAP_FLOW); pScanner->pop(); @@ -122,7 +122,7 @@ namespace YAML if(nextToken.type == TT_FLOW_ENTRY) pScanner->pop(); else if(nextToken.type != TT_FLOW_MAP_END) - throw ParserException(nextToken.line, nextToken.column, ErrorMsg::END_OF_MAP_FLOW); + throw ParserException(nextToken.mark, ErrorMsg::END_OF_MAP_FLOW); // assign the map with the actual pointers m_data[pKey.release()] = pValue.release(); diff --git a/src/node.cpp b/src/node.cpp index f41af12..a1fdbd6 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -47,8 +47,7 @@ namespace YAML return; // save location - m_line = pScanner->peek().line; - m_column = pScanner->peek().column; + m_mark = pScanner->peek().mark; ParseHeader(pScanner, state); @@ -119,7 +118,7 @@ namespace YAML { Token& token = pScanner->peek(); if(m_tag != "") - throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_TAGS); + throw ParserException(token.mark, ErrorMsg::MULTIPLE_TAGS); m_tag = state.TranslateTag(token.value); @@ -132,7 +131,7 @@ namespace YAML { Token& token = pScanner->peek(); if(m_anchor != "") - throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ANCHORS); + throw ParserException(token.mark, ErrorMsg::MULTIPLE_ANCHORS); m_anchor = token.value; m_alias = false; @@ -143,9 +142,9 @@ namespace YAML { Token& token = pScanner->peek(); if(m_anchor != "") - throw ParserException(token.line, token.column, ErrorMsg::MULTIPLE_ALIASES); + throw ParserException(token.mark, ErrorMsg::MULTIPLE_ALIASES); if(m_tag != "") - throw ParserException(token.line, token.column, ErrorMsg::ALIAS_CONTENT); + throw ParserException(token.mark, ErrorMsg::ALIAS_CONTENT); m_anchor = token.value; m_alias = true; diff --git a/src/parser.cpp b/src/parser.cpp index 6b49429..e3b088b 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -98,17 +98,17 @@ namespace YAML void Parser::HandleYamlDirective(Token *pToken) { if(pToken->params.size() != 1) - throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_DIRECTIVE_ARGS); + throw ParserException(pToken->mark, ErrorMsg::YAML_DIRECTIVE_ARGS); std::stringstream str(pToken->params[0]); str >> m_state.version.major; str.get(); str >> m_state.version.minor; if(!str || str.peek() != EOF) - throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_VERSION + pToken->params[0]); + throw ParserException(pToken->mark, ErrorMsg::YAML_VERSION + pToken->params[0]); if(m_state.version.major > 1) - throw ParserException(pToken->line, pToken->column, ErrorMsg::YAML_MAJOR_VERSION); + throw ParserException(pToken->mark, ErrorMsg::YAML_MAJOR_VERSION); // TODO: warning on major == 1, minor > 2? } @@ -118,7 +118,7 @@ namespace YAML void Parser::HandleTagDirective(Token *pToken) { if(pToken->params.size() != 2) - throw ParserException(pToken->line, pToken->column, ErrorMsg::TAG_DIRECTIVE_ARGS); + throw ParserException(pToken->mark, ErrorMsg::TAG_DIRECTIVE_ARGS); std::string handle = pToken->params[0], prefix = pToken->params[1]; m_state.tags[handle] = prefix; diff --git a/src/scanner.cpp b/src/scanner.cpp index c89b105..f4bf55e 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -98,7 +98,7 @@ namespace YAML VerifySimpleKey(); // maybe need to end some blocks - PopIndentTo(INPUT.column); + PopIndentTo(INPUT.column()); // ***** // And now branch based on the next few characters! @@ -108,14 +108,14 @@ namespace YAML if(!INPUT) return EndStream(); - if(INPUT.column == 0 && INPUT.peek() == Keys::Directive) + if(INPUT.column() == 0 && INPUT.peek() == Keys::Directive) return ScanDirective(); // document token - if(INPUT.column == 0 && Exp::DocStart.Matches(INPUT)) + if(INPUT.column() == 0 && Exp::DocStart.Matches(INPUT)) return ScanDocStart(); - if(INPUT.column == 0 && Exp::DocEnd.Matches(INPUT)) + if(INPUT.column() == 0 && Exp::DocEnd.Matches(INPUT)) return ScanDocEnd(); // flow start/end/entry @@ -158,7 +158,7 @@ namespace YAML return ScanPlainScalar(); // don't know what it is! - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::UNKNOWN_TOKEN); + throw ParserException(INPUT.mark(), ErrorMsg::UNKNOWN_TOKEN); } // ScanToNextToken @@ -230,8 +230,8 @@ namespace YAML void Scanner::EndStream() { // force newline - if(INPUT.column > 0) - INPUT.column = 0; + if(INPUT.column() > 0) + INPUT.ResetColumn(); PopIndentTo(-1); VerifyAllSimpleKeys(); @@ -257,9 +257,9 @@ namespace YAML // now push m_indents.push(column); if(sequence) - m_tokens.push(Token(TT_BLOCK_SEQ_START, INPUT.line, INPUT.column)); + m_tokens.push(Token(TT_BLOCK_SEQ_START, INPUT.mark())); else - m_tokens.push(Token(TT_BLOCK_MAP_START, INPUT.line, INPUT.column)); + m_tokens.push(Token(TT_BLOCK_MAP_START, INPUT.mark())); return &m_tokens.back(); } @@ -276,7 +276,7 @@ namespace YAML // now pop away while(!m_indents.empty() && m_indents.top() > column) { m_indents.pop(); - m_tokens.push(Token(TT_BLOCK_END, INPUT.line, INPUT.column)); + m_tokens.push(Token(TT_BLOCK_END, INPUT.mark())); } } @@ -309,13 +309,12 @@ namespace YAML // . Does not parse any more tokens. void Scanner::ThrowParserException(const std::string& msg) const { - int line = -1, column = -1; + Mark mark = Mark::null(); if(!m_tokens.empty()) { const Token& token = m_tokens.front(); - line = token.line; - column = token.column; + mark = token.mark; } - throw ParserException(line, column, msg); + throw ParserException(mark, msg); } void Scanner::ClearAnchors() diff --git a/src/scanner.h b/src/scanner.h index f2f7df2..ffe1d5e 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -48,12 +48,13 @@ namespace YAML bool IsWhitespaceToBeEaten(char ch); struct SimpleKey { - SimpleKey(int pos_, int line_, int column_, int flowLevel_); + SimpleKey(const Mark& mark_, int flowLevel_); void Validate(); void Invalidate(); - - int pos, line, column, flowLevel; + + Mark mark; + int flowLevel; Token *pMapStart, *pKey; }; diff --git a/src/scanscalar.cpp b/src/scanscalar.cpp index 4649237..b4e33f7 100644 --- a/src/scanscalar.cpp +++ b/src/scanscalar.cpp @@ -32,11 +32,11 @@ namespace YAML break; // document indicator? - if(INPUT.column == 0 && Exp::DocIndicator.Matches(INPUT)) { + if(INPUT.column() == 0 && Exp::DocIndicator.Matches(INPUT)) { if(params.onDocIndicator == BREAK) break; else if(params.onDocIndicator == THROW) - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::DOC_IN_SCALAR); + throw ParserException(INPUT.mark(), ErrorMsg::DOC_IN_SCALAR); } foundNonEmptyLine = true; @@ -62,12 +62,12 @@ namespace YAML // eof? if we're looking to eat something, then we throw if(!INPUT) { if(params.eatEnd) - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::EOF_IN_SCALAR); + throw ParserException(INPUT.mark(), ErrorMsg::EOF_IN_SCALAR); break; } // doc indicator? - if(params.onDocIndicator == BREAK && INPUT.column == 0 && Exp::DocIndicator.Matches(INPUT)) + if(params.onDocIndicator == BREAK && INPUT.column() == 0 && Exp::DocIndicator.Matches(INPUT)) break; // are we done via character match? @@ -87,18 +87,18 @@ namespace YAML // Phase #3: scan initial spaces // first the required indentation - while(INPUT.peek() == ' ' && (INPUT.column < params.indent || (params.detectIndent && !foundNonEmptyLine))) + while(INPUT.peek() == ' ' && (INPUT.column() < params.indent || (params.detectIndent && !foundNonEmptyLine))) INPUT.eat(1); // update indent if we're auto-detecting if(params.detectIndent && !foundNonEmptyLine) - params.indent = std::max(params.indent, INPUT.column); + params.indent = std::max(params.indent, INPUT.column()); // and then the rest of the whitespace while(Exp::Blank.Matches(INPUT)) { // we check for tabs that masquerade as indentation - if(INPUT.peek() == '\t'&& INPUT.column < params.indent && params.onTabInIndentation == THROW) - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::TAB_IN_INDENTATION); + if(INPUT.peek() == '\t'&& INPUT.column() < params.indent && params.onTabInIndentation == THROW) + throw ParserException(INPUT.mark(), ErrorMsg::TAB_IN_INDENTATION); if(!params.eatLeadingWhitespace) break; @@ -113,7 +113,7 @@ namespace YAML // for block scalars, we always start with a newline, so we should ignore it (not fold or keep) bool useNewLine = pastOpeningBreak; // and for folded scalars, we don't fold the very last newline to a space - if(params.fold && !emptyLine && INPUT.column < params.indent) + if(params.fold && !emptyLine && INPUT.column() < params.indent) useNewLine = false; if(useNewLine) { @@ -128,7 +128,7 @@ namespace YAML pastOpeningBreak = true; // are we done via indentation? - if(!emptyLine && INPUT.column < params.indent) { + if(!emptyLine && INPUT.column() < params.indent) { params.leadingSpaces = true; break; } diff --git a/src/scantoken.cpp b/src/scantoken.cpp index bb8373a..3699b4d 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -25,7 +25,7 @@ namespace YAML m_simpleKeyAllowed = false; // store pos and eat indicator - int line = INPUT.line, column = INPUT.column; + Mark mark = INPUT.mark(); INPUT.eat(1); // read name @@ -50,7 +50,7 @@ namespace YAML params.push_back(param); } - Token token(TT_DIRECTIVE, line, column); + Token token(TT_DIRECTIVE, mark); token.value = name; token.params = params; m_tokens.push(token); @@ -64,9 +64,9 @@ namespace YAML m_simpleKeyAllowed = false; // eat - int line = INPUT.line, column = INPUT.column; + Mark mark = INPUT.mark(); INPUT.eat(3); - m_tokens.push(Token(TT_DOC_START, line, column)); + m_tokens.push(Token(TT_DOC_START, mark)); } // DocEnd @@ -77,9 +77,9 @@ namespace YAML m_simpleKeyAllowed = false; // eat - int line = INPUT.line, column = INPUT.column; + Mark mark = INPUT.mark(); INPUT.eat(3); - m_tokens.push(Token(TT_DOC_END, line, column)); + m_tokens.push(Token(TT_DOC_END, mark)); } // FlowStart @@ -91,26 +91,26 @@ namespace YAML m_simpleKeyAllowed = true; // eat - int line = INPUT.line, column = INPUT.column; + Mark mark = INPUT.mark(); char ch = INPUT.get(); TOKEN_TYPE type = (ch == Keys::FlowSeqStart ? TT_FLOW_SEQ_START : TT_FLOW_MAP_START); - m_tokens.push(Token(type, line, column)); + m_tokens.push(Token(type, mark)); } // FlowEnd void Scanner::ScanFlowEnd() { if(m_flowLevel == 0) - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::FLOW_END); + throw ParserException(INPUT.mark(), ErrorMsg::FLOW_END); m_flowLevel--; m_simpleKeyAllowed = false; // eat - int line = INPUT.line, column = INPUT.column; + Mark mark = INPUT.mark(); char ch = INPUT.get(); TOKEN_TYPE type = (ch == Keys::FlowSeqEnd ? TT_FLOW_SEQ_END : TT_FLOW_MAP_END); - m_tokens.push(Token(type, line, column)); + m_tokens.push(Token(type, mark)); } // FlowEntry @@ -119,9 +119,9 @@ namespace YAML m_simpleKeyAllowed = true; // eat - int line = INPUT.line, column = INPUT.column; + Mark mark = INPUT.mark(); INPUT.eat(1); - m_tokens.push(Token(TT_FLOW_ENTRY, line, column)); + m_tokens.push(Token(TT_FLOW_ENTRY, mark)); } // BlockEntry @@ -129,19 +129,19 @@ namespace YAML { // we better be in the block context! if(m_flowLevel > 0) - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::BLOCK_ENTRY); + throw ParserException(INPUT.mark(), ErrorMsg::BLOCK_ENTRY); // can we put it here? if(!m_simpleKeyAllowed) - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::BLOCK_ENTRY); + throw ParserException(INPUT.mark(), ErrorMsg::BLOCK_ENTRY); - PushIndentTo(INPUT.column, true); + PushIndentTo(INPUT.column(), true); m_simpleKeyAllowed = true; // eat - int line = INPUT.line, column = INPUT.column; + Mark mark = INPUT.mark(); INPUT.eat(1); - m_tokens.push(Token(TT_BLOCK_ENTRY, line, column)); + m_tokens.push(Token(TT_BLOCK_ENTRY, mark)); } // Key @@ -150,9 +150,9 @@ namespace YAML // handle keys diffently in the block context (and manage indents) if(m_flowLevel == 0) { if(!m_simpleKeyAllowed) - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::MAP_KEY); + throw ParserException(INPUT.mark(), ErrorMsg::MAP_KEY); - PushIndentTo(INPUT.column, false); + PushIndentTo(INPUT.column(), false); } // can only put a simple key here if we're in block context @@ -162,9 +162,9 @@ namespace YAML m_simpleKeyAllowed = false; // eat - int line = INPUT.line, column = INPUT.column; + Mark mark = INPUT.mark(); INPUT.eat(1); - m_tokens.push(Token(TT_KEY, line, column)); + m_tokens.push(Token(TT_KEY, mark)); } // Value @@ -178,9 +178,9 @@ namespace YAML // handle values diffently in the block context (and manage indents) if(m_flowLevel == 0) { if(!m_simpleKeyAllowed) - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::MAP_VALUE); + throw ParserException(INPUT.mark(), ErrorMsg::MAP_VALUE); - PushIndentTo(INPUT.column, false); + PushIndentTo(INPUT.column(), false); } // can only put a simple key here if we're in block context @@ -191,9 +191,9 @@ namespace YAML } // eat - int line = INPUT.line, column = INPUT.column; + Mark mark = INPUT.mark(); INPUT.eat(1); - m_tokens.push(Token(TT_VALUE, line, column)); + m_tokens.push(Token(TT_VALUE, mark)); } // AnchorOrAlias @@ -208,7 +208,7 @@ namespace YAML m_simpleKeyAllowed = false; // eat the indicator - int line = INPUT.line, column = INPUT.column; + Mark mark = INPUT.mark(); char indicator = INPUT.get(); alias = (indicator == Keys::Alias); @@ -218,14 +218,14 @@ namespace YAML // we need to have read SOMETHING! if(name.empty()) - throw ParserException(INPUT.line, INPUT.column, alias ? ErrorMsg::ALIAS_NOT_FOUND : ErrorMsg::ANCHOR_NOT_FOUND); + throw ParserException(INPUT.mark(), alias ? ErrorMsg::ALIAS_NOT_FOUND : ErrorMsg::ANCHOR_NOT_FOUND); // and needs to end correctly if(INPUT && !Exp::AnchorEnd.Matches(INPUT)) - throw ParserException(INPUT.line, INPUT.column, alias ? ErrorMsg::CHAR_IN_ALIAS : ErrorMsg::CHAR_IN_ANCHOR); + throw ParserException(INPUT.mark(), alias ? ErrorMsg::CHAR_IN_ALIAS : ErrorMsg::CHAR_IN_ANCHOR); // and we're done - Token token(alias ? TT_ALIAS : TT_ANCHOR, line, column); + Token token(alias ? TT_ALIAS : TT_ANCHOR, mark); token.value = name; m_tokens.push(token); } @@ -241,7 +241,7 @@ namespace YAML m_simpleKeyAllowed = false; // eat the indicator - int line = INPUT.line, column = INPUT.column; + Mark mark = INPUT.mark(); handle += INPUT.get(); // read the handle @@ -262,7 +262,7 @@ namespace YAML handle = "!"; } - Token token(TT_TAG, line, column); + Token token(TT_TAG, mark); token.value = handle; token.params.push_back(suffix); m_tokens.push(token); @@ -289,7 +289,7 @@ namespace YAML if(m_simpleKeyAllowed) InsertSimpleKey(); - int line = INPUT.line, column = INPUT.column; + Mark mark = INPUT.mark(); scalar = ScanScalar(INPUT, params); // can have a simple key only if we ended the scalar by starting a new line @@ -297,9 +297,9 @@ namespace YAML // finally, check and see if we ended on an illegal character //if(Exp::IllegalCharInScalar.Matches(INPUT)) - // throw ParserException(INPUT.line, INPUT.column, ErrorMsg::CHAR_IN_SCALAR); + // throw ParserException(INPUT.mark(), ErrorMsg::CHAR_IN_SCALAR); - Token token(TT_SCALAR, line, column); + Token token(TT_SCALAR, mark); token.value = scalar; m_tokens.push(token); } @@ -329,7 +329,7 @@ namespace YAML if(m_simpleKeyAllowed) InsertSimpleKey(); - int line = INPUT.line, column = INPUT.column; + Mark mark = INPUT.mark(); // now eat that opening quote INPUT.get(); @@ -338,7 +338,7 @@ namespace YAML scalar = ScanScalar(INPUT, params); m_simpleKeyAllowed = false; - Token token(TT_SCALAR, line, column); + Token token(TT_SCALAR, mark); token.value = scalar; m_tokens.push(token); } @@ -356,7 +356,7 @@ namespace YAML params.detectIndent = true; // eat block indicator ('|' or '>') - int line = INPUT.line, column = INPUT.column; + Mark mark = INPUT.mark(); char indicator = INPUT.get(); params.fold = (indicator == Keys::FoldedScalar); @@ -370,7 +370,7 @@ namespace YAML params.chomp = STRIP; else if(Exp::Digit.Matches(ch)) { if(ch == '0') - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::ZERO_INDENT_IN_BLOCK); + throw ParserException(INPUT.mark(), ErrorMsg::ZERO_INDENT_IN_BLOCK); params.indent = ch - '0'; params.detectIndent = false; @@ -388,7 +388,7 @@ namespace YAML // if it's not a line break, then we ran into a bad character inline if(INPUT && !Exp::Break.Matches(INPUT)) - throw ParserException(INPUT.line, INPUT.column, ErrorMsg::CHAR_IN_BLOCK); + throw ParserException(INPUT.mark(), ErrorMsg::CHAR_IN_BLOCK); // set the initial indentation if(m_indents.top() >= 0) @@ -403,7 +403,7 @@ namespace YAML // simple keys always ok after block scalars (since we're gonna start a new line anyways) m_simpleKeyAllowed = true; - Token token(TT_SCALAR, line, column); + Token token(TT_SCALAR, mark); token.value = scalar; m_tokens.push(token); } diff --git a/src/sequence.cpp b/src/sequence.cpp index 30f6c99..65788fd 100644 --- a/src/sequence.cpp +++ b/src/sequence.cpp @@ -68,11 +68,11 @@ namespace YAML while(1) { if(pScanner->empty()) - throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ); + throw ParserException(Mark::null(), ErrorMsg::END_OF_SEQ); Token token = pScanner->peek(); if(token.type != TT_BLOCK_ENTRY && token.type != TT_BLOCK_END) - throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ); + throw ParserException(token.mark, ErrorMsg::END_OF_SEQ); pScanner->pop(); if(token.type == TT_BLOCK_END) @@ -111,7 +111,7 @@ namespace YAML while(1) { if(pScanner->empty()) - throw ParserException(-1, -1, ErrorMsg::END_OF_SEQ_FLOW); + throw ParserException(Mark::null(), ErrorMsg::END_OF_SEQ_FLOW); // first check for end if(pScanner->peek().type == TT_FLOW_SEQ_END) { @@ -129,7 +129,7 @@ namespace YAML if(token.type == TT_FLOW_ENTRY) pScanner->pop(); else if(token.type != TT_FLOW_SEQ_END) - throw ParserException(token.line, token.column, ErrorMsg::END_OF_SEQ_FLOW); + throw ParserException(token.mark, ErrorMsg::END_OF_SEQ_FLOW); } } diff --git a/src/simplekey.cpp b/src/simplekey.cpp index 667d683..f1c0a2b 100644 --- a/src/simplekey.cpp +++ b/src/simplekey.cpp @@ -6,8 +6,8 @@ namespace YAML { - Scanner::SimpleKey::SimpleKey(int pos_, int line_, int column_, int flowLevel_) - : pos(pos_), line(line_), column(column_), flowLevel(flowLevel_), pMapStart(0), pKey(0) + Scanner::SimpleKey::SimpleKey(const Mark& mark_, int flowLevel_) + : mark(mark_), flowLevel(flowLevel_), pMapStart(0), pKey(0) { } @@ -32,15 +32,15 @@ namespace YAML // and saves it on a stack. void Scanner::InsertSimpleKey() { - SimpleKey key(INPUT.pos, INPUT.line, INPUT.column, m_flowLevel); + SimpleKey key(INPUT.mark(), m_flowLevel); // first add a map start, if necessary - key.pMapStart = PushIndentTo(INPUT.column, false); + key.pMapStart = PushIndentTo(INPUT.column(), false); if(key.pMapStart) key.pMapStart->status = TS_UNVERIFIED; // then add the (now unverified) key - m_tokens.push(Token(TT_KEY, INPUT.line, INPUT.column)); + m_tokens.push(Token(TT_KEY, INPUT.mark())); key.pKey = &m_tokens.back(); key.pKey->status = TS_UNVERIFIED; @@ -78,7 +78,7 @@ namespace YAML isValid = false; // also needs to be less than 1024 characters and inline - if(INPUT.line != key.line || INPUT.pos - key.pos > 1024) + if(INPUT.line() != key.mark.line || INPUT.pos() - key.mark.pos > 1024) isValid = false; // invalidate key diff --git a/src/stream.cpp b/src/stream.cpp index 1041654..5cc9ea9 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -179,7 +179,7 @@ namespace YAML } Stream::Stream(std::istream& input) - : pos(0), line(0), column(0), m_input(input), m_nPushedBack(0), + : m_input(input), m_nPushedBack(0), m_pPrefetched(new unsigned char[YAML_PREFETCH_SIZE]), m_nPrefetchedAvailable(0), m_nPrefetchedUsed(0) { @@ -248,11 +248,11 @@ namespace YAML { char ch = peek(); AdvanceCurrent(); - column++; + m_mark.column++; if(ch == '\n') { - column = 0; - line++; + m_mark.column = 0; + m_mark.line++; } return ch; @@ -282,7 +282,7 @@ namespace YAML if (!m_readahead.empty()) { m_readahead.pop_front(); - ++pos; + m_mark.pos++; } ReadAheadTo(0); diff --git a/src/stream.h b/src/stream.h index 697e1b9..dd5add9 100644 --- a/src/stream.h +++ b/src/stream.h @@ -1,6 +1,7 @@ #pragma once #include "noncopyable.h" +#include "mark.h" #include #include #include @@ -28,13 +29,19 @@ namespace YAML void eat(int n = 1); static char eof() { return 0x04; } + + const Mark mark() const { return m_mark; } + int pos() const { return m_mark.pos; } + int line() const { return m_mark.line; } + int column() const { return m_mark.column; } + void ResetColumn() { m_mark.column = 0; } - int pos, line, column; - private: enum CharacterSet {utf8, utf16le, utf16be, utf32le, utf32be}; std::istream& m_input; + Mark m_mark; + CharacterSet m_charSet; unsigned char m_bufPushback[MAX_PARSER_PUSHBACK]; mutable size_t m_nPushedBack; diff --git a/src/token.h b/src/token.h index 8aec243..6fae451 100644 --- a/src/token.h +++ b/src/token.h @@ -1,5 +1,6 @@ #pragma once +#include "mark.h" #include #include #include @@ -50,7 +51,7 @@ namespace YAML }; struct Token { - Token(TOKEN_TYPE type_, int line_, int column_): status(TS_VALID), type(type_), line(line_), column(column_) {} + Token(TOKEN_TYPE type_, const Mark& mark_): status(TS_VALID), type(type_), mark(mark_) {} friend std::ostream& operator << (std::ostream& out, const Token& token) { out << TokenNames[token.type] << std::string(": ") << token.value; @@ -61,7 +62,7 @@ namespace YAML TOKEN_STATUS status; TOKEN_TYPE type; - int line, column; + Mark mark; std::string value; std::vector params; }; diff --git a/yaml-reader/emittertests.cpp b/yaml-reader/emittertests.cpp index 8836c58..1b8e786 100644 --- a/yaml-reader/emittertests.cpp +++ b/yaml-reader/emittertests.cpp @@ -217,7 +217,7 @@ namespace Test out << YAML::Literal << "literal scalar\nthat may span\nmany, many\nlines and have \"whatever\" crazy\tsymbols that we like"; out << YAML::EndSeq; - desiredOutput = "- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\xadouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like"; + desiredOutput = "- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\x0adouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like"; } void AutoLongKeyScalar(YAML::Emitter& out, std::string& desiredOutput) From 4725c4fabbe206c5f6a427c65057d080c31a9d38 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 27 Jul 2009 04:14:19 +0000 Subject: [PATCH 127/295] Forgot to add mark.h --- include/mark.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 include/mark.h diff --git a/include/mark.h b/include/mark.h new file mode 100644 index 0000000..46d1245 --- /dev/null +++ b/include/mark.h @@ -0,0 +1,16 @@ +#pragma once + +namespace YAML +{ + struct Mark { + Mark(): pos(0), line(0), column(0) {} + + static const Mark null() { return Mark(-1, -1, -1); } + + int pos; + int line, column; + + private: + Mark(int pos_, int line_, int column_): pos(pos_), line(line_), column(column_) {} + }; +} From a2bd317397d797194acda9cbde1d54da9f2c1928 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 29 Jul 2009 22:27:20 +0000 Subject: [PATCH 128/295] Added header file inclusion guards --- include/conversion.h | 6 ++++++ include/crt.h | 6 ++++++ include/emitter.h | 6 ++++++ include/emittermanip.h | 6 ++++++ include/exceptions.h | 6 ++++++ include/iterator.h | 6 ++++++ include/mark.h | 6 ++++++ include/node.h | 6 ++++++ include/nodeimpl.h | 6 ++++++ include/noncopyable.h | 6 ++++++ include/ostream.h | 6 ++++++ include/parser.h | 6 ++++++ include/parserstate.h | 6 ++++++ include/stlemitter.h | 6 ++++++ include/yaml.h | 6 ++++++ src/aliascontent.h | 6 ++++++ src/content.h | 6 ++++++ src/emitterstate.h | 6 ++++++ src/emitterutils.h | 6 ++++++ src/exp.h | 6 ++++++ src/indentation.h | 6 ++++++ src/iterpriv.h | 6 ++++++ src/ltnode.h | 6 ++++++ src/map.h | 6 ++++++ src/regex.h | 6 ++++++ src/regeximpl.h | 6 ++++++ src/scalar.h | 6 ++++++ src/scanner.h | 6 ++++++ src/scanscalar.h | 6 ++++++ src/sequence.h | 6 ++++++ src/setting.h | 6 ++++++ src/stream.h | 6 ++++++ src/streamcharsource.h | 6 ++++++ src/stringsource.h | 6 ++++++ src/token.h | 6 ++++++ yaml-reader/tests.h | 7 +++++++ 36 files changed, 217 insertions(+) diff --git a/include/conversion.h b/include/conversion.h index 8c06191..33ad9c8 100644 --- a/include/conversion.h +++ b/include/conversion.h @@ -1,5 +1,9 @@ #pragma once +#ifndef CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include #include @@ -36,3 +40,5 @@ namespace YAML template <> bool Converter::Convert(const std::string& input, std::wstring& output); } + +#endif // CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/crt.h b/include/crt.h index 5c6f96a..667b60a 100644 --- a/include/crt.h +++ b/include/crt.h @@ -1,5 +1,9 @@ #pragma once +#ifndef CRT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define CRT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + // for detecting memory leaks #ifdef _DEBUG @@ -9,3 +13,5 @@ #endif // _DEBUG + +#endif // CRT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/emitter.h b/include/emitter.h index dce2666..c3c284a 100644 --- a/include/emitter.h +++ b/include/emitter.h @@ -1,5 +1,9 @@ #pragma once +#ifndef EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include "emittermanip.h" #include "ostream.h" #include @@ -84,3 +88,5 @@ namespace YAML return emitter.SetLocalIndent(indent); } } + +#endif // EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/emittermanip.h b/include/emittermanip.h index 22e5fd3..2dd83b5 100644 --- a/include/emittermanip.h +++ b/include/emittermanip.h @@ -1,5 +1,9 @@ #pragma once +#ifndef EMITTERMANIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define EMITTERMANIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include namespace YAML @@ -82,3 +86,5 @@ namespace YAML return _Comment(content); } } + +#endif // EMITTERMANIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/exceptions.h b/include/exceptions.h index b70c82a..6c533ca 100644 --- a/include/exceptions.h +++ b/include/exceptions.h @@ -1,5 +1,9 @@ #pragma once +#ifndef EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include "mark.h" #include #include @@ -129,3 +133,5 @@ namespace YAML : Exception(Mark::null(), msg_) {} }; } + +#endif // EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/iterator.h b/include/iterator.h index 3dbd9ee..bb9141f 100644 --- a/include/iterator.h +++ b/include/iterator.h @@ -1,5 +1,9 @@ #pragma once +#ifndef ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + namespace YAML { class Node; @@ -28,3 +32,5 @@ namespace YAML IterPriv *m_pData; }; } + +#endif // ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/mark.h b/include/mark.h index 46d1245..7c3dfb3 100644 --- a/include/mark.h +++ b/include/mark.h @@ -1,5 +1,9 @@ #pragma once +#ifndef MARK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define MARK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + namespace YAML { struct Mark { @@ -14,3 +18,5 @@ namespace YAML Mark(int pos_, int line_, int column_): pos(pos_), line(line_), column(column_) {} }; } + +#endif // MARK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/node.h b/include/node.h index 3ae77c3..587c707 100644 --- a/include/node.h +++ b/include/node.h @@ -1,5 +1,9 @@ #pragma once +#ifndef NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include "conversion.h" #include "exceptions.h" #include "iterator.h" @@ -95,3 +99,5 @@ namespace YAML } #include "nodeimpl.h" + +#endif // NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/nodeimpl.h b/include/nodeimpl.h index 268176f..31ebbf7 100644 --- a/include/nodeimpl.h +++ b/include/nodeimpl.h @@ -1,5 +1,9 @@ #pragma once +#ifndef NODEIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define NODEIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + namespace YAML { // implementation of templated things @@ -63,3 +67,5 @@ namespace YAML return GetValue(std::string(key)); } } + +#endif // NODEIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/noncopyable.h b/include/noncopyable.h index 2ae4c68..577b547 100644 --- a/include/noncopyable.h +++ b/include/noncopyable.h @@ -1,5 +1,9 @@ #pragma once +#ifndef NONCOPYABLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define NONCOPYABLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + namespace YAML { // this is basically boost::noncopyable @@ -14,3 +18,5 @@ namespace YAML const noncopyable& operator = (const noncopyable&); }; } + +#endif // NONCOPYABLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/ostream.h b/include/ostream.h index 4936c44..a5912bb 100644 --- a/include/ostream.h +++ b/include/ostream.h @@ -1,5 +1,9 @@ #pragma once +#ifndef OSTREAM_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define OSTREAM_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include namespace YAML @@ -30,3 +34,5 @@ namespace YAML ostream& operator << (ostream& out, const std::string& str); ostream& operator << (ostream& out, char ch); } + +#endif // OSTREAM_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/parser.h b/include/parser.h index 78ad52c..0ccea84 100644 --- a/include/parser.h +++ b/include/parser.h @@ -1,5 +1,9 @@ #pragma once +#ifndef PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include #include #include @@ -40,3 +44,5 @@ namespace YAML ParserState m_state; }; } + +#endif // PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/parserstate.h b/include/parserstate.h index f8eb97f..1f27a7f 100644 --- a/include/parserstate.h +++ b/include/parserstate.h @@ -1,5 +1,9 @@ #pragma once +#ifndef PARSERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define PARSERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include #include @@ -18,3 +22,5 @@ namespace YAML std::string TranslateTag(const std::string& handle) const; }; } + +#endif // PARSERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/stlemitter.h b/include/stlemitter.h index 5caa872..c2f86ff 100644 --- a/include/stlemitter.h +++ b/include/stlemitter.h @@ -1,5 +1,9 @@ #pragma once +#ifndef STLEMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define STLEMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include #include #include @@ -36,3 +40,5 @@ namespace YAML return emitter; } } + +#endif // STLEMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml.h b/include/yaml.h index b17868e..0f91428 100644 --- a/include/yaml.h +++ b/include/yaml.h @@ -1,5 +1,9 @@ #pragma once +#ifndef YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include "crt.h" #include "parser.h" #include "node.h" @@ -7,3 +11,5 @@ #include "emitter.h" #include "stlemitter.h" #include "exceptions.h" + +#endif // YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/aliascontent.h b/src/aliascontent.h index 55460d7..e19f1d1 100644 --- a/src/aliascontent.h +++ b/src/aliascontent.h @@ -1,5 +1,9 @@ #pragma once +#ifndef ALIASCONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define ALIASCONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include "content.h" namespace YAML @@ -33,3 +37,5 @@ namespace YAML Content* m_pRef; }; } + +#endif // ALIASCONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/content.h b/src/content.h index 5bb7ffa..b9cd311 100644 --- a/src/content.h +++ b/src/content.h @@ -1,5 +1,9 @@ #pragma once +#ifndef CONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define CONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include #include #include "parserstate.h" @@ -47,3 +51,5 @@ namespace YAML protected: }; } + +#endif // CONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/emitterstate.h b/src/emitterstate.h index 1edfa54..fbabe81 100644 --- a/src/emitterstate.h +++ b/src/emitterstate.h @@ -1,5 +1,9 @@ #pragma once +#ifndef EMITTERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define EMITTERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include "setting.h" #include "emittermanip.h" #include @@ -193,3 +197,5 @@ namespace YAML } } } + +#endif // EMITTERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/emitterutils.h b/src/emitterutils.h index 72b30ad..eb99c6c 100644 --- a/src/emitterutils.h +++ b/src/emitterutils.h @@ -1,5 +1,9 @@ #pragma once +#ifndef EMITTERUTILS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define EMITTERUTILS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include "ostream.h" #include @@ -16,3 +20,5 @@ namespace YAML bool WriteAnchor(ostream& out, const std::string& str); } } + +#endif // EMITTERUTILS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/exp.h b/src/exp.h index 12bd6ac..1c36cb3 100644 --- a/src/exp.h +++ b/src/exp.h @@ -1,5 +1,9 @@ #pragma once +#ifndef EXP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define EXP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include "regex.h" #include #include @@ -72,3 +76,5 @@ namespace YAML const char FoldedScalar = '>'; } } + +#endif // EXP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/indentation.h b/src/indentation.h index b21412b..2e2c967 100644 --- a/src/indentation.h +++ b/src/indentation.h @@ -1,5 +1,9 @@ #pragma once +#ifndef INDENTATION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define INDENTATION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include "ostream.h" #include @@ -28,3 +32,5 @@ namespace YAML } } + +#endif // INDENTATION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/iterpriv.h b/src/iterpriv.h index ec38617..d091fbc 100644 --- a/src/iterpriv.h +++ b/src/iterpriv.h @@ -1,5 +1,9 @@ #pragma once +#ifndef ITERPRIV_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define ITERPRIV_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include "ltnode.h" #include #include @@ -23,3 +27,5 @@ namespace YAML std::map ::const_iterator mapIter; }; } + +#endif // ITERPRIV_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/ltnode.h b/src/ltnode.h index 958d0ac..c1672de 100644 --- a/src/ltnode.h +++ b/src/ltnode.h @@ -1,5 +1,9 @@ #pragma once +#ifndef LTNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define LTNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + namespace YAML { class Node; @@ -8,3 +12,5 @@ namespace YAML bool operator()(const Node *pNode1, const Node *pNode2) const; }; } + +#endif // LTNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/map.h b/src/map.h index 71da430..d5b4b31 100644 --- a/src/map.h +++ b/src/map.h @@ -1,5 +1,9 @@ #pragma once +#ifndef MAP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define MAP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include "content.h" #include @@ -36,3 +40,5 @@ namespace YAML node_map m_data; }; } + +#endif // MAP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/regex.h b/src/regex.h index 4152212..59a4833 100644 --- a/src/regex.h +++ b/src/regex.h @@ -1,5 +1,9 @@ #pragma once +#ifndef REGEX_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define REGEX_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include #include @@ -57,3 +61,5 @@ namespace YAML } #include "regeximpl.h" + +#endif // REGEX_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/regeximpl.h b/src/regeximpl.h index f2daa43..a17d76c 100644 --- a/src/regeximpl.h +++ b/src/regeximpl.h @@ -1,5 +1,9 @@ #pragma once +#ifndef REGEXIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define REGEXIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include "stream.h" #include "stringsource.h" #include "streamcharsource.h" @@ -170,3 +174,5 @@ namespace YAML return offset; } } + +#endif // REGEXIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/scalar.h b/src/scalar.h index 3b06684..59bcb7b 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -1,5 +1,9 @@ #pragma once +#ifndef SCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define SCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include "content.h" #include @@ -32,3 +36,5 @@ namespace YAML std::string m_data; }; } + +#endif // SCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/scanner.h b/src/scanner.h index ffe1d5e..36aa917 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -1,5 +1,9 @@ #pragma once +#ifndef SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include #include #include @@ -94,3 +98,5 @@ namespace YAML std::map m_anchors; }; } + +#endif // SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/scanscalar.h b/src/scanscalar.h index ee66213..319a428 100644 --- a/src/scanscalar.h +++ b/src/scanscalar.h @@ -1,5 +1,9 @@ #pragma once +#ifndef SCANSCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define SCANSCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include #include "regex.h" #include "stream.h" @@ -33,3 +37,5 @@ namespace YAML std::string ScanScalar(Stream& INPUT, ScanScalarParams& info); } + +#endif // SCANSCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/sequence.h b/src/sequence.h index 034e8dc..c7e0828 100644 --- a/src/sequence.h +++ b/src/sequence.h @@ -1,5 +1,9 @@ #pragma once +#ifndef SEQUENCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define SEQUENCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include "content.h" #include @@ -39,3 +43,5 @@ namespace YAML std::vector m_data; }; } + +#endif // SEQUENCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/setting.h b/src/setting.h index c67e951..5619c59 100644 --- a/src/setting.h +++ b/src/setting.h @@ -1,5 +1,9 @@ #pragma once +#ifndef SETTING_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define SETTING_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include #include #include "noncopyable.h" @@ -95,3 +99,5 @@ namespace YAML setting_changes m_settingChanges; }; } + +#endif // SETTING_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/stream.h b/src/stream.h index dd5add9..5d78551 100644 --- a/src/stream.h +++ b/src/stream.h @@ -1,5 +1,9 @@ #pragma once +#ifndef STREAM_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define STREAM_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include "noncopyable.h" #include "mark.h" #include @@ -72,3 +76,5 @@ namespace YAML return _ReadAheadTo(i); } } + +#endif // STREAM_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/streamcharsource.h b/src/streamcharsource.h index d8368ac..10debc8 100644 --- a/src/streamcharsource.h +++ b/src/streamcharsource.h @@ -1,5 +1,9 @@ #pragma once +#ifndef STREAMCHARSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define STREAMCHARSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include "noncopyable.h" #include @@ -38,3 +42,5 @@ namespace YAML return source; } } + +#endif // STREAMCHARSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/stringsource.h b/src/stringsource.h index 4b892fe..c4e4c13 100644 --- a/src/stringsource.h +++ b/src/stringsource.h @@ -1,5 +1,9 @@ #pragma once +#ifndef STRINGSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define STRINGSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include namespace YAML @@ -32,3 +36,5 @@ namespace YAML std::size_t m_offset; }; } + +#endif // STRINGSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/token.h b/src/token.h index 6fae451..3c5fb58 100644 --- a/src/token.h +++ b/src/token.h @@ -1,5 +1,9 @@ #pragma once +#ifndef TOKEN_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define TOKEN_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + #include "mark.h" #include #include @@ -67,3 +71,5 @@ namespace YAML std::vector params; }; } + +#endif // TOKEN_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-reader/tests.h b/yaml-reader/tests.h index 20ec4d3..19054a0 100644 --- a/yaml-reader/tests.h +++ b/yaml-reader/tests.h @@ -1,3 +1,8 @@ +#pragma once + +#ifndef TESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define TESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + #include namespace YAML { class Emitter; } @@ -76,3 +81,5 @@ namespace Test { void UnexpectedValue(YAML::Emitter& out, std::string& desiredError); } } + +#endif // TESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 From c043b9c64b4c7bb913b8ab7f48a9386dce54eb09 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 30 Jul 2009 04:42:27 +0000 Subject: [PATCH 129/295] Added support for emitting and represeting null --- include/conversion.h | 4 + include/emitter.h | 2 + include/null.h | 13 + src/conversion.cpp | 6 + src/emitter.cpp | 12 + src/node.cpp | 4 + src/null.cpp | 6 + yaml-reader/emittertests.cpp | 1041 +++++++++++++++++----------------- yaml-reader/tests.cpp | 1 + yaml-reader/tests.h | 1 + 10 files changed, 576 insertions(+), 514 deletions(-) create mode 100644 include/null.h create mode 100644 src/null.cpp diff --git a/include/conversion.h b/include/conversion.h index 33ad9c8..3fe5abd 100644 --- a/include/conversion.h +++ b/include/conversion.h @@ -4,6 +4,7 @@ #define CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#include "null.h" #include #include @@ -37,6 +38,9 @@ namespace YAML template <> bool Converter::Convert(const std::string& input, bool& output); + template <> + bool Converter<_Null>::Convert(const std::string& input, _Null& output); + template <> bool Converter::Convert(const std::string& input, std::wstring& output); } diff --git a/include/emitter.h b/include/emitter.h index c3c284a..055c9c7 100644 --- a/include/emitter.h +++ b/include/emitter.h @@ -6,6 +6,7 @@ #include "emittermanip.h" #include "ostream.h" +#include "null.h" #include #include @@ -51,6 +52,7 @@ namespace YAML Emitter& Write(const _Alias& alias); Emitter& Write(const _Anchor& anchor); Emitter& Write(const _Comment& comment); + Emitter& Write(const _Null& null); private: enum ATOMIC_TYPE { AT_SCALAR, AT_SEQ, AT_BLOCK_SEQ, AT_FLOW_SEQ, AT_MAP, AT_BLOCK_MAP, AT_FLOW_MAP }; diff --git a/include/null.h b/include/null.h new file mode 100644 index 0000000..4729803 --- /dev/null +++ b/include/null.h @@ -0,0 +1,13 @@ +#pragma once + +#ifndef NULL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define NULL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + +namespace YAML +{ + struct _Null {}; + extern _Null Null; +} + +#endif // NULL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 \ No newline at end of file diff --git a/src/conversion.cpp b/src/conversion.cpp index 7a55e1c..904efb0 100644 --- a/src/conversion.cpp +++ b/src/conversion.cpp @@ -83,6 +83,12 @@ namespace YAML return false; } + template <> + bool Converter<_Null>::Convert(const std::string& input, _Null& /*output*/) + { + return input.empty() || input == "~" || input == "null" || input == "Null" || input == "NULL"; + } + template <> bool Converter::Convert(const std::string& input, std::wstring& output) { diff --git a/src/emitter.cpp b/src/emitter.cpp index 15df4e8..ac305b9 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -666,4 +666,16 @@ namespace YAML Utils::WriteComment(m_stream, comment.content, m_pState->GetPostCommentIndent()); return *this; } + + Emitter& Emitter::Write(const _Null& /*null*/) + { + if(!good()) + return *this; + + PreAtomicWrite(); + EmitSeparationIfNecessary(); + m_stream << "~"; + PostAtomicWrite(); + return *this; + } } diff --git a/src/node.cpp b/src/node.cpp index a1fdbd6..5f20e4c 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -10,6 +10,7 @@ #include "aliascontent.h" #include "iterpriv.h" #include "emitter.h" +#include namespace YAML { @@ -85,6 +86,9 @@ namespace YAML m_pContent = new Map; break; default: +// std::stringstream str; +// str << TokenNames[pScanner->peek().type]; +// throw std::runtime_error(str.str()); break; } diff --git a/src/null.cpp b/src/null.cpp new file mode 100644 index 0000000..853d49a --- /dev/null +++ b/src/null.cpp @@ -0,0 +1,6 @@ +#include "null.h" + +namespace YAML +{ + _Null Null; +} diff --git a/yaml-reader/emittertests.cpp b/yaml-reader/emittertests.cpp index 1b8e786..a016bff 100644 --- a/yaml-reader/emittertests.cpp +++ b/yaml-reader/emittertests.cpp @@ -1,514 +1,527 @@ -#include "tests.h" -#include "yaml.h" - -namespace Test -{ - namespace Emitter { - //////////////////////////////////////////////////////////////////////////////////////////////////////// - // correct emitting - - void SimpleScalar(YAML::Emitter& out, std::string& desiredOutput) { - out << "Hello, World!"; - desiredOutput = "Hello, World!"; - } - - void SimpleSeq(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginSeq; - out << "eggs"; - out << "bread"; - out << "milk"; - out << YAML::EndSeq; - - desiredOutput = "- eggs\n- bread\n- milk"; - } - - void SimpleFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::Flow; - out << YAML::BeginSeq; - out << "Larry"; - out << "Curly"; - out << "Moe"; - out << YAML::EndSeq; - - desiredOutput = "[Larry, Curly, Moe]"; - } - - void EmptyFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::Flow; - out << YAML::BeginSeq; - out << YAML::EndSeq; - - desiredOutput = "[]"; - } - - void NestedBlockSeq(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginSeq; - out << "item 1"; - out << YAML::BeginSeq << "subitem 1" << "subitem 2" << YAML::EndSeq; - out << YAML::EndSeq; - - desiredOutput = "- item 1\n-\n - subitem 1\n - subitem 2"; - } - - void NestedFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginSeq; - out << "one"; - out << YAML::Flow << YAML::BeginSeq << "two" << "three" << YAML::EndSeq; - out << YAML::EndSeq; - - desiredOutput = "- one\n- [two, three]"; - } - - void SimpleMap(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginMap; - out << YAML::Key << "name"; - out << YAML::Value << "Ryan Braun"; - out << YAML::Key << "position"; - out << YAML::Value << "3B"; - out << YAML::EndMap; - - desiredOutput = "name: Ryan Braun\nposition: 3B"; - } - - void SimpleFlowMap(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::Flow; - out << YAML::BeginMap; - out << YAML::Key << "shape"; - out << YAML::Value << "square"; - out << YAML::Key << "color"; - out << YAML::Value << "blue"; - out << YAML::EndMap; - - desiredOutput = "{shape: square, color: blue}"; - } - - void MapAndList(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginMap; - out << YAML::Key << "name"; - out << YAML::Value << "Barack Obama"; - out << YAML::Key << "children"; - out << YAML::Value << YAML::BeginSeq << "Sasha" << "Malia" << YAML::EndSeq; - out << YAML::EndMap; - - desiredOutput = "name: Barack Obama\nchildren:\n - Sasha\n - Malia"; - } - - void ListAndMap(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginSeq; - out << "item 1"; - out << YAML::BeginMap; - out << YAML::Key << "pens" << YAML::Value << 8; - out << YAML::Key << "pencils" << YAML::Value << 14; - out << YAML::EndMap; - out << "item 2"; - out << YAML::EndSeq; - - desiredOutput = "- item 1\n-\n pens: 8\n pencils: 14\n- item 2"; - } - - void NestedBlockMap(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginMap; - out << YAML::Key << "name"; - out << YAML::Value << "Fred"; - out << YAML::Key << "grades"; - out << YAML::Value; - out << YAML::BeginMap; - out << YAML::Key << "algebra" << YAML::Value << "A"; - out << YAML::Key << "physics" << YAML::Value << "C+"; - out << YAML::Key << "literature" << YAML::Value << "B"; - out << YAML::EndMap; - out << YAML::EndMap; - - desiredOutput = "name: Fred\ngrades:\n algebra: A\n physics: C+\n literature: B"; - } - - void NestedFlowMap(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::Flow; - out << YAML::BeginMap; - out << YAML::Key << "name"; - out << YAML::Value << "Fred"; - out << YAML::Key << "grades"; - out << YAML::Value; - out << YAML::BeginMap; - out << YAML::Key << "algebra" << YAML::Value << "A"; - out << YAML::Key << "physics" << YAML::Value << "C+"; - out << YAML::Key << "literature" << YAML::Value << "B"; - out << YAML::EndMap; - out << YAML::EndMap; - - desiredOutput = "{name: Fred, grades: {algebra: A, physics: C+, literature: B}}"; - } - - void MapListMix(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginMap; - out << YAML::Key << "name"; - out << YAML::Value << "Bob"; - out << YAML::Key << "position"; - out << YAML::Value; - out << YAML::Flow << YAML::BeginSeq << 2 << 4 << YAML::EndSeq; - out << YAML::Key << "invincible" << YAML::Value << YAML::OnOffBool << false; - out << YAML::EndMap; - - desiredOutput = "name: Bob\nposition: [2, 4]\ninvincible: off"; - } - - void SimpleLongKey(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::LongKey; - out << YAML::BeginMap; - out << YAML::Key << "height"; - out << YAML::Value << "5'9\""; - out << YAML::Key << "weight"; - out << YAML::Value << 145; - out << YAML::EndMap; - - desiredOutput = "? height\n: 5'9\"\n? weight\n: 145"; - } - - void SingleLongKey(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::Key << "age"; - out << YAML::Value << "24"; - out << YAML::LongKey << YAML::Key << "height"; - out << YAML::Value << "5'9\""; - out << YAML::Key << "weight"; - out << YAML::Value << 145; - out << YAML::EndMap; - - desiredOutput = "age: 24\n? height\n: 5'9\"\nweight: 145"; - } - - void ComplexLongKey(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::LongKey; - out << YAML::BeginMap; - out << YAML::Key << YAML::BeginSeq << 1 << 3 << YAML::EndSeq; - out << YAML::Value << "monster"; - out << YAML::Key << YAML::Flow << YAML::BeginSeq << 2 << 0 << YAML::EndSeq; - out << YAML::Value << "demon"; - out << YAML::EndMap; - - desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon"; - } - - void AutoLongKey(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::Key << YAML::BeginSeq << 1 << 3 << YAML::EndSeq; - out << YAML::Value << "monster"; - out << YAML::Key << YAML::Flow << YAML::BeginSeq << 2 << 0 << YAML::EndSeq; - out << YAML::Value << "demon"; - out << YAML::Key << "the origin"; - out << YAML::Value << "angel"; - out << YAML::EndMap; - - desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon\nthe origin: angel"; - } - - void ScalarFormat(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginSeq; - out << "simple scalar"; - out << YAML::SingleQuoted << "explicit single-quoted scalar"; - out << YAML::DoubleQuoted << "explicit double-quoted scalar"; - out << "auto-detected\ndouble-quoted scalar"; - out << "a non-\"auto-detected\" double-quoted scalar"; - out << YAML::Literal << "literal scalar\nthat may span\nmany, many\nlines and have \"whatever\" crazy\tsymbols that we like"; - out << YAML::EndSeq; - - desiredOutput = "- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\x0adouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like"; - } - - void AutoLongKeyScalar(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::Key << YAML::Literal << "multi-line\nscalar"; - out << YAML::Value << "and its value"; - out << YAML::EndMap; - - desiredOutput = "? |\n multi-line\n scalar\n: and its value"; - } - - void LongKeyFlowMap(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::Flow; - out << YAML::BeginMap; - out << YAML::Key << "simple key"; - out << YAML::Value << "and value"; - out << YAML::LongKey << YAML::Key << "long key"; - out << YAML::Value << "and its value"; - out << YAML::EndMap; - - desiredOutput = "{simple key: and value, ? long key: and its value}"; - } - - void BlockMapAsKey(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::Key; - out << YAML::BeginMap; - out << YAML::Key << "key" << YAML::Value << "value"; - out << YAML::Key << "next key" << YAML::Value << "next value"; - out << YAML::EndMap; - out << YAML::Value; - out << "total value"; - out << YAML::EndMap; - - desiredOutput = "?\n key: value\n next key: next value\n: total value"; - } - - void AliasAndAnchor(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginSeq; - out << YAML::Anchor("fred"); - out << YAML::BeginMap; - out << YAML::Key << "name" << YAML::Value << "Fred"; - out << YAML::Key << "age" << YAML::Value << 42; - out << YAML::EndMap; - out << YAML::Alias("fred"); - out << YAML::EndSeq; - - desiredOutput = "- &fred\n name: Fred\n age: 42\n- *fred"; - } - - void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::Key << "receipt"; - out << YAML::Value << "Oz-Ware Purchase Invoice"; - out << YAML::Key << "date"; - out << YAML::Value << "2007-08-06"; - out << YAML::Key << "customer"; - out << YAML::Value; - out << YAML::BeginMap; - out << YAML::Key << "given"; - out << YAML::Value << "Dorothy"; - out << YAML::Key << "family"; - out << YAML::Value << "Gale"; - out << YAML::EndMap; - out << YAML::Key << "items"; - out << YAML::Value; - out << YAML::BeginSeq; - out << YAML::BeginMap; - out << YAML::Key << "part_no"; - out << YAML::Value << "A4786"; - out << YAML::Key << "descrip"; - out << YAML::Value << "Water Bucket (Filled)"; - out << YAML::Key << "price"; - out << YAML::Value << 1.47; - out << YAML::Key << "quantity"; - out << YAML::Value << 4; - out << YAML::EndMap; - out << YAML::BeginMap; - out << YAML::Key << "part_no"; - out << YAML::Value << "E1628"; - out << YAML::Key << "descrip"; - out << YAML::Value << "High Heeled \"Ruby\" Slippers"; - out << YAML::Key << "price"; - out << YAML::Value << 100.27; - out << YAML::Key << "quantity"; - out << YAML::Value << 1; - out << YAML::EndMap; - out << YAML::EndSeq; - out << YAML::Key << "bill-to"; - out << YAML::Value << YAML::Anchor("id001"); - out << YAML::BeginMap; - out << YAML::Key << "street"; - out << YAML::Value << YAML::Literal << "123 Tornado Alley\nSuite 16"; - out << YAML::Key << "city"; - out << YAML::Value << "East Westville"; - out << YAML::Key << "state"; - out << YAML::Value << "KS"; - out << YAML::EndMap; - out << YAML::Key << "ship-to"; - out << YAML::Value << YAML::Alias("id001"); - out << YAML::EndMap; - - desiredOutput = "receipt: Oz-Ware Purchase Invoice\ndate: 2007-08-06\ncustomer:\n given: Dorothy\n family: Gale\nitems:\n -\n part_no: A4786\n descrip: Water Bucket (Filled)\n price: 1.47\n quantity: 4\n -\n part_no: E1628\n descrip: High Heeled \"Ruby\" Slippers\n price: 100.27\n quantity: 1\nbill-to: &id001\n street: |\n 123 Tornado Alley\n Suite 16\n city: East Westville\n state: KS\nship-to: *id001"; - } - - void STLContainers(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginSeq; - std::vector primes; - primes.push_back(2); - primes.push_back(3); - primes.push_back(5); - primes.push_back(7); - primes.push_back(11); - primes.push_back(13); - out << YAML::Flow << primes; - std::map ages; - ages["Daniel"] = 26; - ages["Jesse"] = 24; - out << ages; - out << YAML::EndSeq; - - desiredOutput = "- [2, 3, 5, 7, 11, 13]\n-\n Daniel: 26\n Jesse: 24"; - } - - void SimpleComment(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::Key << "method"; - out << YAML::Value << "least squares" << YAML::Comment("should we change this method?"); - out << YAML::EndMap; - - desiredOutput = "method: least squares # should we change this method?"; - } - - void MultiLineComment(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginSeq; - out << "item 1" << YAML::Comment("really really long\ncomment that couldn't possibly\nfit on one line"); - out << "item 2"; - out << YAML::EndSeq; - - desiredOutput = "- item 1 # really really long\n # comment that couldn't possibly\n # fit on one line\n- item 2"; - } - - void ComplexComments(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::LongKey << YAML::Key << "long key" << YAML::Comment("long key"); - out << YAML::Value << "value"; - out << YAML::EndMap; - - desiredOutput = "? long key # long key\n: value"; - } - - void Indentation(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::Indent(4); - out << YAML::BeginSeq; - out << YAML::BeginMap; - out << YAML::Key << "key 1" << YAML::Value << "value 1"; - out << YAML::Key << "key 2" << YAML::Value << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; - out << YAML::EndMap; - out << YAML::EndSeq; - - desiredOutput = "-\n key 1: value 1\n key 2:\n - a\n - b\n - c"; - } - - void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) - { - out.SetIndent(4); - out.SetMapFormat(YAML::LongKey); - - out << YAML::BeginSeq; - out << YAML::BeginMap; - out << YAML::Key << "key 1" << YAML::Value << "value 1"; - out << YAML::Key << "key 2" << YAML::Value << YAML::Flow << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; - out << YAML::EndMap; - out << YAML::EndSeq; - - desiredOutput = "-\n ? key 1\n : value 1\n ? key 2\n : [a, b, c]"; - } - - void ComplexGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginSeq; - out << YAML::Block; - out << YAML::BeginMap; - out << YAML::Key << "key 1" << YAML::Value << "value 1"; - out << YAML::Key << "key 2" << YAML::Value; - out.SetSeqFormat(YAML::Flow); - out << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; - out << YAML::EndMap; - out << YAML::BeginMap; - out << YAML::Key << YAML::BeginSeq << 1 << 2 << YAML::EndSeq; - out << YAML::Value << YAML::BeginMap << YAML::Key << "a" << YAML::Value << "b" << YAML::EndMap; - out << YAML::EndMap; - out << YAML::EndSeq; - - desiredOutput = "-\n key 1: value 1\n key 2: [a, b, c]\n-\n ? [1, 2]\n :\n a: b"; - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////// - // incorrect emitting - - void ExtraEndSeq(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::UNEXPECTED_END_SEQ; - - out << YAML::BeginSeq; - out << "Hello"; - out << "World"; - out << YAML::EndSeq; - out << YAML::EndSeq; - } - - void ExtraEndMap(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::UNEXPECTED_END_MAP; - - out << YAML::BeginMap; - out << YAML::Key << "Hello" << YAML::Value << "World"; - out << YAML::EndMap; - out << YAML::EndMap; - } - - void BadSingleQuoted(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::SINGLE_QUOTED_CHAR; - - out << YAML::SingleQuoted << "Hello\nWorld"; - } - - void InvalidAnchor(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::INVALID_ANCHOR; - - out << YAML::BeginSeq; - out << YAML::Anchor("new\nline") << "Test"; - out << YAML::EndSeq; - } - - void InvalidAlias(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::INVALID_ALIAS; - - out << YAML::BeginSeq; - out << YAML::Alias("new\nline"); - out << YAML::EndSeq; - } - - void MissingKey(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::EXPECTED_KEY_TOKEN; - - out << YAML::BeginMap; - out << YAML::Key << "key" << YAML::Value << "value"; - out << "missing key" << YAML::Value << "value"; - out << YAML::EndMap; - } - - void MissingValue(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::EXPECTED_VALUE_TOKEN; - - out << YAML::BeginMap; - out << YAML::Key << "key" << "value"; - out << YAML::EndMap; - } - - void UnexpectedKey(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::UNEXPECTED_KEY_TOKEN; - - out << YAML::BeginSeq; - out << YAML::Key << "hi"; - out << YAML::EndSeq; - } - - void UnexpectedValue(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::UNEXPECTED_VALUE_TOKEN; - - out << YAML::BeginSeq; - out << YAML::Value << "hi"; - out << YAML::EndSeq; - } - } -} +#include "tests.h" +#include "yaml.h" + +namespace Test +{ + namespace Emitter { + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // correct emitting + + void SimpleScalar(YAML::Emitter& out, std::string& desiredOutput) { + out << "Hello, World!"; + desiredOutput = "Hello, World!"; + } + + void SimpleSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginSeq; + out << "eggs"; + out << "bread"; + out << "milk"; + out << YAML::EndSeq; + + desiredOutput = "- eggs\n- bread\n- milk"; + } + + void SimpleFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::Flow; + out << YAML::BeginSeq; + out << "Larry"; + out << "Curly"; + out << "Moe"; + out << YAML::EndSeq; + + desiredOutput = "[Larry, Curly, Moe]"; + } + + void EmptyFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::Flow; + out << YAML::BeginSeq; + out << YAML::EndSeq; + + desiredOutput = "[]"; + } + + void NestedBlockSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginSeq; + out << "item 1"; + out << YAML::BeginSeq << "subitem 1" << "subitem 2" << YAML::EndSeq; + out << YAML::EndSeq; + + desiredOutput = "- item 1\n-\n - subitem 1\n - subitem 2"; + } + + void NestedFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginSeq; + out << "one"; + out << YAML::Flow << YAML::BeginSeq << "two" << "three" << YAML::EndSeq; + out << YAML::EndSeq; + + desiredOutput = "- one\n- [two, three]"; + } + + void SimpleMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Ryan Braun"; + out << YAML::Key << "position"; + out << YAML::Value << "3B"; + out << YAML::EndMap; + + desiredOutput = "name: Ryan Braun\nposition: 3B"; + } + + void SimpleFlowMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::Flow; + out << YAML::BeginMap; + out << YAML::Key << "shape"; + out << YAML::Value << "square"; + out << YAML::Key << "color"; + out << YAML::Value << "blue"; + out << YAML::EndMap; + + desiredOutput = "{shape: square, color: blue}"; + } + + void MapAndList(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Barack Obama"; + out << YAML::Key << "children"; + out << YAML::Value << YAML::BeginSeq << "Sasha" << "Malia" << YAML::EndSeq; + out << YAML::EndMap; + + desiredOutput = "name: Barack Obama\nchildren:\n - Sasha\n - Malia"; + } + + void ListAndMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginSeq; + out << "item 1"; + out << YAML::BeginMap; + out << YAML::Key << "pens" << YAML::Value << 8; + out << YAML::Key << "pencils" << YAML::Value << 14; + out << YAML::EndMap; + out << "item 2"; + out << YAML::EndSeq; + + desiredOutput = "- item 1\n-\n pens: 8\n pencils: 14\n- item 2"; + } + + void NestedBlockMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Fred"; + out << YAML::Key << "grades"; + out << YAML::Value; + out << YAML::BeginMap; + out << YAML::Key << "algebra" << YAML::Value << "A"; + out << YAML::Key << "physics" << YAML::Value << "C+"; + out << YAML::Key << "literature" << YAML::Value << "B"; + out << YAML::EndMap; + out << YAML::EndMap; + + desiredOutput = "name: Fred\ngrades:\n algebra: A\n physics: C+\n literature: B"; + } + + void NestedFlowMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::Flow; + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Fred"; + out << YAML::Key << "grades"; + out << YAML::Value; + out << YAML::BeginMap; + out << YAML::Key << "algebra" << YAML::Value << "A"; + out << YAML::Key << "physics" << YAML::Value << "C+"; + out << YAML::Key << "literature" << YAML::Value << "B"; + out << YAML::EndMap; + out << YAML::EndMap; + + desiredOutput = "{name: Fred, grades: {algebra: A, physics: C+, literature: B}}"; + } + + void MapListMix(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Bob"; + out << YAML::Key << "position"; + out << YAML::Value; + out << YAML::Flow << YAML::BeginSeq << 2 << 4 << YAML::EndSeq; + out << YAML::Key << "invincible" << YAML::Value << YAML::OnOffBool << false; + out << YAML::EndMap; + + desiredOutput = "name: Bob\nposition: [2, 4]\ninvincible: off"; + } + + void SimpleLongKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::LongKey; + out << YAML::BeginMap; + out << YAML::Key << "height"; + out << YAML::Value << "5'9\""; + out << YAML::Key << "weight"; + out << YAML::Value << 145; + out << YAML::EndMap; + + desiredOutput = "? height\n: 5'9\"\n? weight\n: 145"; + } + + void SingleLongKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << "age"; + out << YAML::Value << "24"; + out << YAML::LongKey << YAML::Key << "height"; + out << YAML::Value << "5'9\""; + out << YAML::Key << "weight"; + out << YAML::Value << 145; + out << YAML::EndMap; + + desiredOutput = "age: 24\n? height\n: 5'9\"\nweight: 145"; + } + + void ComplexLongKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::LongKey; + out << YAML::BeginMap; + out << YAML::Key << YAML::BeginSeq << 1 << 3 << YAML::EndSeq; + out << YAML::Value << "monster"; + out << YAML::Key << YAML::Flow << YAML::BeginSeq << 2 << 0 << YAML::EndSeq; + out << YAML::Value << "demon"; + out << YAML::EndMap; + + desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon"; + } + + void AutoLongKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << YAML::BeginSeq << 1 << 3 << YAML::EndSeq; + out << YAML::Value << "monster"; + out << YAML::Key << YAML::Flow << YAML::BeginSeq << 2 << 0 << YAML::EndSeq; + out << YAML::Value << "demon"; + out << YAML::Key << "the origin"; + out << YAML::Value << "angel"; + out << YAML::EndMap; + + desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon\nthe origin: angel"; + } + + void ScalarFormat(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << "simple scalar"; + out << YAML::SingleQuoted << "explicit single-quoted scalar"; + out << YAML::DoubleQuoted << "explicit double-quoted scalar"; + out << "auto-detected\ndouble-quoted scalar"; + out << "a non-\"auto-detected\" double-quoted scalar"; + out << YAML::Literal << "literal scalar\nthat may span\nmany, many\nlines and have \"whatever\" crazy\tsymbols that we like"; + out << YAML::EndSeq; + + desiredOutput = "- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\x0adouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like"; + } + + void AutoLongKeyScalar(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << YAML::Literal << "multi-line\nscalar"; + out << YAML::Value << "and its value"; + out << YAML::EndMap; + + desiredOutput = "? |\n multi-line\n scalar\n: and its value"; + } + + void LongKeyFlowMap(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Flow; + out << YAML::BeginMap; + out << YAML::Key << "simple key"; + out << YAML::Value << "and value"; + out << YAML::LongKey << YAML::Key << "long key"; + out << YAML::Value << "and its value"; + out << YAML::EndMap; + + desiredOutput = "{simple key: and value, ? long key: and its value}"; + } + + void BlockMapAsKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key; + out << YAML::BeginMap; + out << YAML::Key << "key" << YAML::Value << "value"; + out << YAML::Key << "next key" << YAML::Value << "next value"; + out << YAML::EndMap; + out << YAML::Value; + out << "total value"; + out << YAML::EndMap; + + desiredOutput = "?\n key: value\n next key: next value\n: total value"; + } + + void AliasAndAnchor(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << YAML::Anchor("fred"); + out << YAML::BeginMap; + out << YAML::Key << "name" << YAML::Value << "Fred"; + out << YAML::Key << "age" << YAML::Value << 42; + out << YAML::EndMap; + out << YAML::Alias("fred"); + out << YAML::EndSeq; + + desiredOutput = "- &fred\n name: Fred\n age: 42\n- *fred"; + } + + void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << "receipt"; + out << YAML::Value << "Oz-Ware Purchase Invoice"; + out << YAML::Key << "date"; + out << YAML::Value << "2007-08-06"; + out << YAML::Key << "customer"; + out << YAML::Value; + out << YAML::BeginMap; + out << YAML::Key << "given"; + out << YAML::Value << "Dorothy"; + out << YAML::Key << "family"; + out << YAML::Value << "Gale"; + out << YAML::EndMap; + out << YAML::Key << "items"; + out << YAML::Value; + out << YAML::BeginSeq; + out << YAML::BeginMap; + out << YAML::Key << "part_no"; + out << YAML::Value << "A4786"; + out << YAML::Key << "descrip"; + out << YAML::Value << "Water Bucket (Filled)"; + out << YAML::Key << "price"; + out << YAML::Value << 1.47; + out << YAML::Key << "quantity"; + out << YAML::Value << 4; + out << YAML::EndMap; + out << YAML::BeginMap; + out << YAML::Key << "part_no"; + out << YAML::Value << "E1628"; + out << YAML::Key << "descrip"; + out << YAML::Value << "High Heeled \"Ruby\" Slippers"; + out << YAML::Key << "price"; + out << YAML::Value << 100.27; + out << YAML::Key << "quantity"; + out << YAML::Value << 1; + out << YAML::EndMap; + out << YAML::EndSeq; + out << YAML::Key << "bill-to"; + out << YAML::Value << YAML::Anchor("id001"); + out << YAML::BeginMap; + out << YAML::Key << "street"; + out << YAML::Value << YAML::Literal << "123 Tornado Alley\nSuite 16"; + out << YAML::Key << "city"; + out << YAML::Value << "East Westville"; + out << YAML::Key << "state"; + out << YAML::Value << "KS"; + out << YAML::EndMap; + out << YAML::Key << "ship-to"; + out << YAML::Value << YAML::Alias("id001"); + out << YAML::EndMap; + + desiredOutput = "receipt: Oz-Ware Purchase Invoice\ndate: 2007-08-06\ncustomer:\n given: Dorothy\n family: Gale\nitems:\n -\n part_no: A4786\n descrip: Water Bucket (Filled)\n price: 1.47\n quantity: 4\n -\n part_no: E1628\n descrip: High Heeled \"Ruby\" Slippers\n price: 100.27\n quantity: 1\nbill-to: &id001\n street: |\n 123 Tornado Alley\n Suite 16\n city: East Westville\n state: KS\nship-to: *id001"; + } + + void STLContainers(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + std::vector primes; + primes.push_back(2); + primes.push_back(3); + primes.push_back(5); + primes.push_back(7); + primes.push_back(11); + primes.push_back(13); + out << YAML::Flow << primes; + std::map ages; + ages["Daniel"] = 26; + ages["Jesse"] = 24; + out << ages; + out << YAML::EndSeq; + + desiredOutput = "- [2, 3, 5, 7, 11, 13]\n-\n Daniel: 26\n Jesse: 24"; + } + + void SimpleComment(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << "method"; + out << YAML::Value << "least squares" << YAML::Comment("should we change this method?"); + out << YAML::EndMap; + + desiredOutput = "method: least squares # should we change this method?"; + } + + void MultiLineComment(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << "item 1" << YAML::Comment("really really long\ncomment that couldn't possibly\nfit on one line"); + out << "item 2"; + out << YAML::EndSeq; + + desiredOutput = "- item 1 # really really long\n # comment that couldn't possibly\n # fit on one line\n- item 2"; + } + + void ComplexComments(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::LongKey << YAML::Key << "long key" << YAML::Comment("long key"); + out << YAML::Value << "value"; + out << YAML::EndMap; + + desiredOutput = "? long key # long key\n: value"; + } + + void Indentation(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Indent(4); + out << YAML::BeginSeq; + out << YAML::BeginMap; + out << YAML::Key << "key 1" << YAML::Value << "value 1"; + out << YAML::Key << "key 2" << YAML::Value << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; + out << YAML::EndMap; + out << YAML::EndSeq; + + desiredOutput = "-\n key 1: value 1\n key 2:\n - a\n - b\n - c"; + } + + void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) + { + out.SetIndent(4); + out.SetMapFormat(YAML::LongKey); + + out << YAML::BeginSeq; + out << YAML::BeginMap; + out << YAML::Key << "key 1" << YAML::Value << "value 1"; + out << YAML::Key << "key 2" << YAML::Value << YAML::Flow << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; + out << YAML::EndMap; + out << YAML::EndSeq; + + desiredOutput = "-\n ? key 1\n : value 1\n ? key 2\n : [a, b, c]"; + } + + void ComplexGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << YAML::Block; + out << YAML::BeginMap; + out << YAML::Key << "key 1" << YAML::Value << "value 1"; + out << YAML::Key << "key 2" << YAML::Value; + out.SetSeqFormat(YAML::Flow); + out << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; + out << YAML::EndMap; + out << YAML::BeginMap; + out << YAML::Key << YAML::BeginSeq << 1 << 2 << YAML::EndSeq; + out << YAML::Value << YAML::BeginMap << YAML::Key << "a" << YAML::Value << "b" << YAML::EndMap; + out << YAML::EndMap; + out << YAML::EndSeq; + + desiredOutput = "-\n key 1: value 1\n key 2: [a, b, c]\n-\n ? [1, 2]\n :\n a: b"; + } + + void Null(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << YAML::Null; + out << YAML::BeginMap; + out << YAML::Key << "null value" << YAML::Value << YAML::Null; + out << YAML::Key << YAML::Null << YAML::Value << "null key"; + out << YAML::EndMap; + out << YAML::EndSeq; + + desiredOutput = "- ~\n-\n null value: ~\n ~: null key"; + } + + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // incorrect emitting + + void ExtraEndSeq(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::UNEXPECTED_END_SEQ; + + out << YAML::BeginSeq; + out << "Hello"; + out << "World"; + out << YAML::EndSeq; + out << YAML::EndSeq; + } + + void ExtraEndMap(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::UNEXPECTED_END_MAP; + + out << YAML::BeginMap; + out << YAML::Key << "Hello" << YAML::Value << "World"; + out << YAML::EndMap; + out << YAML::EndMap; + } + + void BadSingleQuoted(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::SINGLE_QUOTED_CHAR; + + out << YAML::SingleQuoted << "Hello\nWorld"; + } + + void InvalidAnchor(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::INVALID_ANCHOR; + + out << YAML::BeginSeq; + out << YAML::Anchor("new\nline") << "Test"; + out << YAML::EndSeq; + } + + void InvalidAlias(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::INVALID_ALIAS; + + out << YAML::BeginSeq; + out << YAML::Alias("new\nline"); + out << YAML::EndSeq; + } + + void MissingKey(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::EXPECTED_KEY_TOKEN; + + out << YAML::BeginMap; + out << YAML::Key << "key" << YAML::Value << "value"; + out << "missing key" << YAML::Value << "value"; + out << YAML::EndMap; + } + + void MissingValue(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::EXPECTED_VALUE_TOKEN; + + out << YAML::BeginMap; + out << YAML::Key << "key" << "value"; + out << YAML::EndMap; + } + + void UnexpectedKey(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::UNEXPECTED_KEY_TOKEN; + + out << YAML::BeginSeq; + out << YAML::Key << "hi"; + out << YAML::EndSeq; + } + + void UnexpectedValue(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::UNEXPECTED_VALUE_TOKEN; + + out << YAML::BeginSeq; + out << YAML::Value << "hi"; + out << YAML::EndSeq; + } + } +} diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp index a499cb3..3476962 100644 --- a/yaml-reader/tests.cpp +++ b/yaml-reader/tests.cpp @@ -351,6 +351,7 @@ namespace Test RunEmitterTest(&Emitter::Indentation, "indentation", passed); RunEmitterTest(&Emitter::SimpleGlobalSettings, "simple global settings", passed); RunEmitterTest(&Emitter::ComplexGlobalSettings, "complex global settings", passed); + RunEmitterTest(&Emitter::Null, "null", passed); RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed); RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed); diff --git a/yaml-reader/tests.h b/yaml-reader/tests.h index 19054a0..106b44c 100644 --- a/yaml-reader/tests.h +++ b/yaml-reader/tests.h @@ -68,6 +68,7 @@ namespace Test { void Indentation(YAML::Emitter& out, std::string& desiredOutput); void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput); void ComplexGlobalSettings(YAML::Emitter& out, std::string& desiredOutput); + void Null(YAML::Emitter& out, std::string& desiredOutput); // incorrect emitting void ExtraEndSeq(YAML::Emitter& out, std::string& desiredError); From 49265fa12bd396608bf57b2d9d96426d91f5578a Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 30 Jul 2009 05:54:40 +0000 Subject: [PATCH 130/295] Fixed empty scalar in sequence bug --- src/node.cpp | 2 +- src/sequence.cpp | 9 +++++++++ src/token.h | 6 ++++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/node.cpp b/src/node.cpp index 5f20e4c..587f4b3 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -264,7 +264,7 @@ namespace YAML if(node.m_pContent) node.m_pContent->Write(out); else - out << ""; + out << Null; return out; } diff --git a/src/sequence.cpp b/src/sequence.cpp index 65788fd..ad49fe3 100644 --- a/src/sequence.cpp +++ b/src/sequence.cpp @@ -4,6 +4,7 @@ #include "scanner.h" #include "token.h" #include "emitter.h" +#include namespace YAML { @@ -80,6 +81,14 @@ namespace YAML Node *pNode = new Node; m_data.push_back(pNode); + + // check for null + if(!pScanner->empty()) { + const Token& token = pScanner->peek(); + if(token.type == TT_BLOCK_ENTRY || token.type == TT_BLOCK_END) + continue; + } + pNode->Parse(pScanner, state); } } diff --git a/src/token.h b/src/token.h index 3c5fb58..8bddc77 100644 --- a/src/token.h +++ b/src/token.h @@ -30,7 +30,8 @@ namespace YAML TT_ANCHOR, TT_ALIAS, TT_TAG, - TT_SCALAR + TT_SCALAR, + TT_NULL }; const std::string TokenNames[] = { @@ -51,7 +52,8 @@ namespace YAML "ANCHOR", "ALIAS", "TAG", - "SCALAR" + "SCALAR", + "NULL" }; struct Token { From cb2b5783fa386ebdb4640edb67aca69574683121 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 30 Jul 2009 06:49:09 +0000 Subject: [PATCH 131/295] Fixed null key/value bug, added tests --- include/null.h | 3 ++ src/exp.h | 6 ++-- src/map.cpp | 16 +++++++---- src/node.cpp | 7 +++-- src/token.h | 6 ++-- yaml-reader/parsertests.cpp | 57 +++++++++++++++++++++++++++++++++++++ yaml-reader/tests.cpp | 5 +++- yaml-reader/tests.h | 3 ++ 8 files changed, 87 insertions(+), 16 deletions(-) diff --git a/include/null.h b/include/null.h index 4729803..c7c43cc 100644 --- a/include/null.h +++ b/include/null.h @@ -7,6 +7,9 @@ namespace YAML { struct _Null {}; + inline bool operator == (const _Null&, const _Null&) { return true; } + inline bool operator != (const _Null&, const _Null&) { return false; } + extern _Null Null; } diff --git a/src/exp.h b/src/exp.h index 1c36cb3..1b5ac74 100644 --- a/src/exp.h +++ b/src/exp.h @@ -33,10 +33,10 @@ namespace YAML const RegEx DocStart = RegEx("---") + (BlankOrBreak || RegEx()); const RegEx DocEnd = RegEx("...") + (BlankOrBreak || RegEx()); const RegEx DocIndicator = DocStart || DocEnd; - const RegEx BlockEntry = RegEx('-') + BlankOrBreak; + const RegEx BlockEntry = RegEx('-') + (BlankOrBreak || RegEx()); const RegEx Key = RegEx('?'), KeyInFlow = RegEx('?') + BlankOrBreak; - const RegEx Value = RegEx(':') + BlankOrBreak, + const RegEx Value = RegEx(':') + (BlankOrBreak || RegEx()), ValueInFlow = RegEx(':') + BlankOrBreak; const RegEx Comment = RegEx('#'); const RegEx AnchorEnd = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak; @@ -48,7 +48,7 @@ namespace YAML // . In the flow context ? is illegal and : and - must not be followed with a space. const RegEx PlainScalar = !(BlankOrBreak || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:", REGEX_OR) + Blank)), PlainScalarInFlow = !(BlankOrBreak || RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-:", REGEX_OR) + Blank)); - const RegEx EndScalar = RegEx(':') + BlankOrBreak, + const RegEx EndScalar = RegEx(':') + (BlankOrBreak || RegEx()), EndScalarInFlow = (RegEx(':') + BlankOrBreak) || RegEx(",?[]{}", REGEX_OR); const RegEx EscSingleQuote = RegEx("\'\'"); diff --git a/src/map.cpp b/src/map.cpp index 46a6977..4682829 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -61,17 +61,21 @@ namespace YAML throw ParserException(Mark::null(), ErrorMsg::END_OF_MAP); Token token = pScanner->peek(); - if(token.type != TT_KEY && token.type != TT_BLOCK_END) + if(token.type != TT_KEY && token.type != TT_VALUE && token.type != TT_BLOCK_END) throw ParserException(token.mark, ErrorMsg::END_OF_MAP); - pScanner->pop(); - if(token.type == TT_BLOCK_END) + if(token.type == TT_BLOCK_END) { + pScanner->pop(); break; + } std::auto_ptr pKey(new Node), pValue(new Node); - - // grab key - pKey->Parse(pScanner, state); + + // grab key (if non-null) + if(token.type == TT_KEY) { + pScanner->pop(); + pKey->Parse(pScanner, state); + } // now grab value (optional) if(!pScanner->empty() && pScanner->peek().type == TT_VALUE) { diff --git a/src/node.cpp b/src/node.cpp index 587f4b3..a2230d9 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -243,8 +243,11 @@ namespace YAML bool Node::GetScalar(std::string& s) const { - if(!m_pContent) - return false; + if(!m_pContent) { + s = "~"; + return true; + } + return m_pContent->GetScalar(s); } diff --git a/src/token.h b/src/token.h index 8bddc77..3c5fb58 100644 --- a/src/token.h +++ b/src/token.h @@ -30,8 +30,7 @@ namespace YAML TT_ANCHOR, TT_ALIAS, TT_TAG, - TT_SCALAR, - TT_NULL + TT_SCALAR }; const std::string TokenNames[] = { @@ -52,8 +51,7 @@ namespace YAML "ANCHOR", "ALIAS", "TAG", - "SCALAR", - "NULL" + "SCALAR" }; struct Token { diff --git a/yaml-reader/parsertests.cpp b/yaml-reader/parsertests.cpp index b78cc53..721ceb9 100644 --- a/yaml-reader/parsertests.cpp +++ b/yaml-reader/parsertests.cpp @@ -247,5 +247,62 @@ namespace Test return true; } + + bool NullBlockSeqEntry() + { + std::string input = "- hello\n-\n- world"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc[0] >> output; + if(output != "hello") + return false; + doc[1] >> output; + if(output != "~") + return false; + doc[2] >> output; + if(output != "world") + return false; + + return true; + } + + bool NullBlockMapKey() + { + std::string input = ": empty key"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc[YAML::Null] >> output; + if(output != "empty key") + return false; + + return true; + } + + bool NullBlockMapValue() + { + std::string input = "empty value:"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc["empty value"] >> output; + if(output != "~") + return false; + + return true; + } } } diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp index 3476962..f434c03 100644 --- a/yaml-reader/tests.cpp +++ b/yaml-reader/tests.cpp @@ -263,7 +263,10 @@ namespace Test RunParserTest(&Parser::FlowSeq, "flow seq", passed); RunParserTest(&Parser::FlowMap, "flow map", passed); RunParserTest(&Parser::QuotedSimpleKeys, "quoted simple keys", passed); - + RunParserTest(&Parser::NullBlockSeqEntry, "null block seq entry", passed); + RunParserTest(&Parser::NullBlockMapKey, "null block map key", passed); + RunParserTest(&Parser::NullBlockMapValue, "null block map value", passed); + RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed); RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed); RunEncodingTest(&EncodeToUtf16LE, false, "UTF-16LE, no BOM", passed); diff --git a/yaml-reader/tests.h b/yaml-reader/tests.h index 106b44c..e205166 100644 --- a/yaml-reader/tests.h +++ b/yaml-reader/tests.h @@ -34,6 +34,9 @@ namespace Test { bool FlowSeq(); bool FlowMap(); bool QuotedSimpleKeys(); + bool NullBlockSeqEntry(); + bool NullBlockMapKey(); + bool NullBlockMapValue(); } namespace Emitter { From 952f72233ea42055d10150104efa1651bae2d5b6 Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 31 Jul 2009 05:07:21 +0000 Subject: [PATCH 132/295] Added IsNull function --- include/null.h | 4 ++++ src/null.cpp | 6 ++++++ yaml-reader/parsertests.cpp | 7 ++----- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/include/null.h b/include/null.h index c7c43cc..7036f98 100644 --- a/include/null.h +++ b/include/null.h @@ -6,10 +6,14 @@ namespace YAML { + class Node; + struct _Null {}; inline bool operator == (const _Null&, const _Null&) { return true; } inline bool operator != (const _Null&, const _Null&) { return false; } + bool IsNull(const Node& node); + extern _Null Null; } diff --git a/src/null.cpp b/src/null.cpp index 853d49a..faa05fb 100644 --- a/src/null.cpp +++ b/src/null.cpp @@ -1,6 +1,12 @@ #include "null.h" +#include "node.h" namespace YAML { _Null Null; + + bool IsNull(const Node& node) + { + return node.Read(Null); + } } diff --git a/yaml-reader/parsertests.cpp b/yaml-reader/parsertests.cpp index 721ceb9..3b2e28d 100644 --- a/yaml-reader/parsertests.cpp +++ b/yaml-reader/parsertests.cpp @@ -261,8 +261,7 @@ namespace Test doc[0] >> output; if(output != "hello") return false; - doc[1] >> output; - if(output != "~") + if(!IsNull(doc[1])) return false; doc[2] >> output; if(output != "world") @@ -297,9 +296,7 @@ namespace Test YAML::Node doc; parser.GetNextDocument(doc); - std::string output; - doc["empty value"] >> output; - if(output != "~") + if(!IsNull(doc["empty value"])) return false; return true; From c456eab7cdbacee5838a13d4359b650f1f11731b Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 31 Jul 2009 18:26:42 +0000 Subject: [PATCH 133/295] Fixed out-of-bounds memory access --- src/scanner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scanner.cpp b/src/scanner.cpp index f4bf55e..5848d77 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -167,7 +167,7 @@ namespace YAML { while(1) { // first eat whitespace - while(IsWhitespaceToBeEaten(INPUT.peek())) + while(INPUT && IsWhitespaceToBeEaten(INPUT.peek())) INPUT.eat(1); // then eat a comment From d1c888f57a06eb2ab9491613b7e5f25225aaeda3 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 19 Aug 2009 03:37:19 +0000 Subject: [PATCH 134/295] Added templated Read() function that creates the output variable itself (so you don't need to have a temp variable) --- include/node.h | 3 +++ include/nodeimpl.h | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/include/node.h b/include/node.h index 587c707..5ee1273 100644 --- a/include/node.h +++ b/include/node.h @@ -49,6 +49,9 @@ namespace YAML template bool Read(T& value) const; + template + const T Read() const; + template friend void operator >> (const Node& node, T& value); diff --git a/include/nodeimpl.h b/include/nodeimpl.h index 31ebbf7..606a5be 100644 --- a/include/nodeimpl.h +++ b/include/nodeimpl.h @@ -16,6 +16,13 @@ namespace YAML return Convert(scalar, value); } + template + inline const T Node::Read() const { + T value; + *this >> value; + return value; + } + template inline void operator >> (const Node& node, T& value) { if(!node.Read(value)) From c45372e2f38afc9e64aabe75a206985d759cb098 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 19 Aug 2009 05:09:12 +0000 Subject: [PATCH 135/295] Added 'yaml-cpp: ' to the exception messages --- include/exceptions.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/exceptions.h b/include/exceptions.h index 6c533ca..8a246f0 100644 --- a/include/exceptions.h +++ b/include/exceptions.h @@ -68,7 +68,7 @@ namespace YAML Exception(const Mark& mark_, const std::string& msg_) : mark(mark_), msg(msg_) { std::stringstream output; - output << "Error at line " << mark.line+1 << ", column " << mark.column+1 << ": " << msg; + output << "yaml-cpp: error at line " << mark.line+1 << ", column " << mark.column+1 << ": " << msg; what_ = output.str(); } virtual ~Exception() throw() {} From 770d6de545eb32eb84a3c7dd1029b12f2f559343 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 19 Aug 2009 20:58:07 +0000 Subject: [PATCH 136/295] Converted indexing to std::size_t, and fixed the Node templated overloads to properly index any index type (determining what is an index type is a bit of a hack - it should be is_convertible (I think), but I just explicitly wrote down a list) --- include/node.h | 23 ++++++++++------- include/nodeimpl.h | 39 ++++++++++++++++------------ include/nodeutil.h | 60 ++++++++++++++++++++++++++++++++++++++++++++ src/aliascontent.cpp | 4 +-- src/aliascontent.h | 4 +-- src/content.h | 4 +-- src/conversion.cpp | 2 +- src/emitterutils.cpp | 12 ++++----- src/exp.cpp | 2 +- src/node.cpp | 28 +++++---------------- src/ostream.cpp | 4 +-- src/regex.cpp | 2 +- src/regeximpl.h | 6 ++--- src/scanscalar.cpp | 4 +-- src/sequence.cpp | 12 ++++----- src/sequence.h | 4 +-- src/token.h | 2 +- 17 files changed, 134 insertions(+), 78 deletions(-) create mode 100644 include/nodeutil.h diff --git a/include/node.h b/include/node.h index 5ee1273..9b6eb22 100644 --- a/include/node.h +++ b/include/node.h @@ -40,7 +40,7 @@ namespace YAML // accessors Iterator begin() const; Iterator end() const; - unsigned size() const; + std::size_t size() const; // extraction of scalars bool GetScalar(std::string& s) const; @@ -55,19 +55,17 @@ namespace YAML template friend void operator >> (const Node& node, T& value); - // just for maps + // retrieval for maps and sequences template const Node *FindValue(const T& key) const; - const Node *FindValue(const char *key) const; - + template const Node& operator [] (const T& key) const; + + // specific to maps + const Node *FindValue(const char *key) const; const Node& operator [] (const char *key) const; - // just for sequences - const Node& operator [] (unsigned u) const; - const Node& operator [] (int i) const; - // for anchors/aliases const Node *Identity() const { return m_pIdentity; } bool IsAlias() const { return m_alias; } @@ -81,10 +79,17 @@ namespace YAML friend bool operator < (const Node& n1, const Node& n2); private: + // helper for sequences + template friend struct _FindFromNodeAtIndex; + const Node *FindAtIndex(std::size_t i) const; + // helper for maps template const Node& GetValue(const T& key) const; - + + template + const Node *FindValueForKey(const T& key) const; + // helpers for parsing void ParseHeader(Scanner *pScanner, const ParserState& state); void ParseTag(Scanner *pScanner, const ParserState& state); diff --git a/include/nodeimpl.h b/include/nodeimpl.h index 606a5be..f513fd5 100644 --- a/include/nodeimpl.h +++ b/include/nodeimpl.h @@ -4,6 +4,8 @@ #define NODEIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#include "nodeutil.h" + namespace YAML { // implementation of templated things @@ -31,9 +33,18 @@ namespace YAML template inline const Node *Node::FindValue(const T& key) const { - if(!m_pContent) - return 0; - + switch(GetType()) { + case CT_MAP: + return FindValueForKey(key); + case CT_SEQUENCE: + return FindFromNodeAtIndex(*this, key); + default: + return 0; + } + } + + template + inline const Node *Node::FindValueForKey(const T& key) const { for(Iterator it=begin();it!=end();++it) { T t; if(it.first().Read(t)) { @@ -45,24 +56,16 @@ namespace YAML return 0; } - inline const Node *Node::FindValue(const char *key) const { - return FindValue(std::string(key)); - } - template inline const Node& Node::GetValue(const T& key) const { if(!m_pContent) throw BadDereference(); - for(Iterator it=begin();it!=end();++it) { - T t; - if(it.first().Read(t)) { - if(key == t) - return it.second(); - } - } - - throw MakeTypedKeyNotFound(m_mark, key); + const Node *pValue = FindValue(key); + if(!pValue) + throw MakeTypedKeyNotFound(m_mark, key); + + return *pValue; } template @@ -70,6 +73,10 @@ namespace YAML return GetValue(key); } + inline const Node *Node::FindValue(const char *key) const { + return FindValue(std::string(key)); + } + inline const Node& Node::operator [] (const char *key) const { return GetValue(std::string(key)); } diff --git a/include/nodeutil.h b/include/nodeutil.h new file mode 100644 index 0000000..eb2956f --- /dev/null +++ b/include/nodeutil.h @@ -0,0 +1,60 @@ +#pragma once + +#ifndef NODEUTIL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define NODEUTIL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + +namespace YAML +{ + template + struct is_same_type { + enum { value = false }; + }; + + template + struct is_same_type { + enum { value = true }; + }; + + template + struct is_index_type_with_check { + enum { value = false }; + }; + + template <> struct is_index_type_with_check { enum { value = true }; }; + +#define MAKE_INDEX_TYPE(Type) \ + template <> struct is_index_type_with_check::value> { enum { value = true }; } + + MAKE_INDEX_TYPE(int); + MAKE_INDEX_TYPE(unsigned); + MAKE_INDEX_TYPE(short); + MAKE_INDEX_TYPE(unsigned short); + MAKE_INDEX_TYPE(long); + MAKE_INDEX_TYPE(unsigned long); + +#undef MAKE_INDEX_TYPE; + + template + struct is_index_type: public is_index_type_with_check {}; + + // messing around with template stuff to get the right overload for operator [] for a sequence + template + struct _FindFromNodeAtIndex { + const Node *pRet; + _FindFromNodeAtIndex(const Node&, const T&): pRet(0) {} + }; + + template + struct _FindFromNodeAtIndex { + const Node *pRet; + _FindFromNodeAtIndex(const Node& node, const T& key): pRet(node.FindAtIndex(static_cast(key))) {} + }; + + template + inline const Node *FindFromNodeAtIndex(const Node& node, const T& key) { + return _FindFromNodeAtIndex::value>(node, key).pRet; + } +} + +#endif // NODEUTIL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/aliascontent.cpp b/src/aliascontent.cpp index 9f98571..7d49b71 100644 --- a/src/aliascontent.cpp +++ b/src/aliascontent.cpp @@ -37,12 +37,12 @@ namespace YAML return m_pRef->GetEnd(i); } - Node* AliasContent::GetNode(unsigned n) const + Node* AliasContent::GetNode(std::size_t n) const { return m_pRef->GetNode(n); } - unsigned AliasContent::GetSize() const + std::size_t AliasContent::GetSize() const { return m_pRef->GetSize(); } diff --git a/src/aliascontent.h b/src/aliascontent.h index e19f1d1..e6448fe 100644 --- a/src/aliascontent.h +++ b/src/aliascontent.h @@ -20,8 +20,8 @@ namespace YAML virtual bool GetBegin(std::map ::const_iterator&) const; virtual bool GetEnd(std::vector ::const_iterator&) const; virtual bool GetEnd(std::map ::const_iterator&) const; - virtual Node* GetNode(unsigned) const; - virtual unsigned GetSize() const; + virtual Node* GetNode(std::size_t) const; + virtual std::size_t GetSize() const; virtual bool IsScalar() const; virtual bool IsMap() const; virtual bool IsSequence() const; diff --git a/src/content.h b/src/content.h index b9cd311..1574691 100644 --- a/src/content.h +++ b/src/content.h @@ -33,8 +33,8 @@ namespace YAML virtual bool GetBegin(std::map ::const_iterator&) const { return false; } virtual bool GetEnd(std::vector ::const_iterator&) const { return false; } virtual bool GetEnd(std::map ::const_iterator&) const { return false; } - virtual Node *GetNode(unsigned) const { return 0; } - virtual unsigned GetSize() const { return 0; } + virtual Node *GetNode(std::size_t) const { return 0; } + virtual std::size_t GetSize() const { return 0; } virtual bool IsScalar() const { return false; } virtual bool IsMap() const { return false; } virtual bool IsSequence() const { return false; } diff --git a/src/conversion.cpp b/src/conversion.cpp index 904efb0..fa199bb 100644 --- a/src/conversion.cpp +++ b/src/conversion.cpp @@ -22,7 +22,7 @@ namespace template bool IsEntirely(const std::string& str, T func) { - for(unsigned i=0;ipop(); } @@ -209,7 +209,7 @@ namespace YAML // size // . Returns the size of this node, if it's a sequence node. // . Otherwise, returns zero. - unsigned Node::size() const + std::size_t Node::size() const { if(!m_pContent) return 0; @@ -217,28 +217,12 @@ namespace YAML return m_pContent->GetSize(); } - const Node& Node::operator [] (unsigned u) const + const Node *Node::FindAtIndex(std::size_t i) const { if(!m_pContent) - throw BadDereference(); - - Node *pNode = m_pContent->GetNode(u); - if(pNode) - return *pNode; - - return GetValue(u); - } - - const Node& Node::operator [] (int i) const - { - if(!m_pContent) - throw BadDereference(); - - Node *pNode = m_pContent->GetNode(i); - if(pNode) - return *pNode; - - return GetValue(i); + return 0; + + return m_pContent->GetNode(i); } bool Node::GetScalar(std::string& s) const diff --git a/src/ostream.cpp b/src/ostream.cpp index 9f75684..463a450 100644 --- a/src/ostream.cpp +++ b/src/ostream.cpp @@ -43,8 +43,8 @@ namespace YAML ostream& operator << (ostream& out, const char *str) { - unsigned length = std::strlen(str); - for(unsigned i=0;i inline int RegEx::MatchOpOr(const Source& source) const { - for(unsigned i=0;i= 0) return n; @@ -140,7 +140,7 @@ namespace YAML template inline int RegEx::MatchOpAnd(const Source& source) const { int first = -1; - for(unsigned i=0;i inline int RegEx::MatchOpSeq(const Source& source) const { int offset = 0; - for(unsigned i=0;im_data.size(); + std::size_t n = m_data.size(), m = pSeq->m_data.size(); if(n < m) return -1; else if(n > m) return 1; - for(unsigned i=0;iCompare(*pSeq->m_data[i]); if(cmp != 0) return cmp; diff --git a/src/sequence.h b/src/sequence.h index c7e0828..f158882 100644 --- a/src/sequence.h +++ b/src/sequence.h @@ -20,8 +20,8 @@ namespace YAML void Clear(); virtual bool GetBegin(std::vector ::const_iterator& it) const; virtual bool GetEnd(std::vector ::const_iterator& it) const; - virtual Node *GetNode(unsigned i) const; - virtual unsigned GetSize() const; + virtual Node *GetNode(std::size_t i) const; + virtual std::size_t GetSize() const; virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(Emitter& out) const; diff --git a/src/token.h b/src/token.h index 3c5fb58..060861a 100644 --- a/src/token.h +++ b/src/token.h @@ -59,7 +59,7 @@ namespace YAML friend std::ostream& operator << (std::ostream& out, const Token& token) { out << TokenNames[token.type] << std::string(": ") << token.value; - for(unsigned i=0;i Date: Sat, 22 Aug 2009 00:25:37 +0000 Subject: [PATCH 137/295] Removed the std::wstring conversion --- include/conversion.h | 3 --- src/conversion.cpp | 15 --------------- 2 files changed, 18 deletions(-) diff --git a/include/conversion.h b/include/conversion.h index 3fe5abd..f449816 100644 --- a/include/conversion.h +++ b/include/conversion.h @@ -40,9 +40,6 @@ namespace YAML template <> bool Converter<_Null>::Convert(const std::string& input, _Null& output); - - template <> - bool Converter::Convert(const std::string& input, std::wstring& output); } #endif // CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/conversion.cpp b/src/conversion.cpp index fa199bb..1240e27 100644 --- a/src/conversion.cpp +++ b/src/conversion.cpp @@ -1,6 +1,5 @@ #include "conversion.h" #include -#include //////////////////////////////////////////////////////////////// // Specializations for converting a string to specific types @@ -88,19 +87,5 @@ namespace YAML { return input.empty() || input == "~" || input == "null" || input == "Null" || input == "NULL"; } - - template <> - bool Converter::Convert(const std::string& input, std::wstring& output) - { - output.clear(); - output.resize(std::mbstowcs(NULL, input.data(), input.size())); - std::mbstowcs( - (wchar_t *) output.data(), - input.data(), - input.size() - ); - - return true; - } } From 8fcd09f30bb42873798f495d74a8c7c1c9dedb61 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 24 Aug 2009 18:23:20 +0000 Subject: [PATCH 138/295] Cleaned up --- include/nodeutil.h | 2 +- include/null.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/nodeutil.h b/include/nodeutil.h index eb2956f..1be6b69 100644 --- a/include/nodeutil.h +++ b/include/nodeutil.h @@ -33,7 +33,7 @@ namespace YAML MAKE_INDEX_TYPE(long); MAKE_INDEX_TYPE(unsigned long); -#undef MAKE_INDEX_TYPE; +#undef MAKE_INDEX_TYPE template struct is_index_type: public is_index_type_with_check {}; diff --git a/include/null.h b/include/null.h index 7036f98..3857683 100644 --- a/include/null.h +++ b/include/null.h @@ -17,4 +17,5 @@ namespace YAML extern _Null Null; } -#endif // NULL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 \ No newline at end of file +#endif // NULL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + From fc22d55b5368c87676fcc0626b94f3de7b191f51 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 24 Aug 2009 20:10:42 +0000 Subject: [PATCH 139/295] Added Node::Clone function --- include/node.h | 5 +++++ src/aliascontent.cpp | 5 +++++ src/aliascontent.h | 2 ++ src/content.h | 2 ++ src/map.cpp | 14 ++++++++++++++ src/map.h | 9 +++++++-- src/node.cpp | 15 +++++++++++++++ src/scalar.cpp | 10 ++++++++++ src/scalar.h | 4 ++++ src/sequence.cpp | 11 +++++++++++ src/sequence.h | 3 +++ 11 files changed, 78 insertions(+), 2 deletions(-) diff --git a/include/node.h b/include/node.h index 9b6eb22..1d39ede 100644 --- a/include/node.h +++ b/include/node.h @@ -14,6 +14,7 @@ #include #include #include +#include namespace YAML { @@ -30,6 +31,7 @@ namespace YAML ~Node(); void Clear(); + std::auto_ptr Clone() const; void Parse(Scanner *pScanner, const ParserState& state); CONTENT_TYPE GetType() const; @@ -89,6 +91,9 @@ namespace YAML template 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, const ParserState& state); diff --git a/src/aliascontent.cpp b/src/aliascontent.cpp index 7d49b71..aa0f399 100644 --- a/src/aliascontent.cpp +++ b/src/aliascontent.cpp @@ -8,6 +8,11 @@ namespace YAML { } + Content *AliasContent::Clone() const + { + return 0; // TODO: how to clone an alias? + } + void AliasContent::Parse(Scanner * /*pScanner*/, const ParserState& /*state*/) { } diff --git a/src/aliascontent.h b/src/aliascontent.h index e6448fe..d4cbb56 100644 --- a/src/aliascontent.h +++ b/src/aliascontent.h @@ -12,6 +12,8 @@ namespace YAML { public: AliasContent(Content *pNodeContent); + + virtual Content *Clone() const; virtual void Parse(Scanner* pScanner, const ParserState& state); virtual void Write(Emitter&) const; diff --git a/src/content.h b/src/content.h index 1574691..71e7037 100644 --- a/src/content.h +++ b/src/content.h @@ -25,6 +25,8 @@ namespace YAML public: Content(); virtual ~Content(); + + virtual Content *Clone() const = 0; virtual void Parse(Scanner *pScanner, const ParserState& state) = 0; virtual void Write(Emitter& out) const = 0; diff --git a/src/map.cpp b/src/map.cpp index 4682829..f0038fc 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -12,6 +12,15 @@ 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 pKey = it->first->Clone(); + std::auto_ptr pValue = it->second->Clone(); + m_data[pKey.release()] = pValue.release(); + } + } Map::~Map() { @@ -27,6 +36,11 @@ namespace YAML m_data.clear(); } + Content *Map::Clone() const + { + return new Map(m_data); + } + bool Map::GetBegin(std::map ::const_iterator& it) const { it = m_data.begin(); diff --git a/src/map.h b/src/map.h index d5b4b31..fc448b5 100644 --- a/src/map.h +++ b/src/map.h @@ -13,11 +13,17 @@ namespace YAML class Map: public Content { + private: + typedef std::map node_map; + public: Map(); + Map(const node_map& data); virtual ~Map(); void Clear(); + virtual Content *Clone() const; + virtual bool GetBegin(std::map ::const_iterator& it) const; virtual bool GetEnd(std::map ::const_iterator& it) const; virtual void Parse(Scanner *pScanner, const ParserState& state); @@ -35,8 +41,7 @@ namespace YAML void ParseBlock(Scanner *pScanner, const ParserState& state); void ParseFlow(Scanner *pScanner, const ParserState& state); - protected: - typedef std::map node_map; + private: node_map m_data; }; } diff --git a/src/node.cpp b/src/node.cpp index 165f822..7a460f3 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -24,6 +24,13 @@ namespace YAML { } + 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(m_pContent) + m_pContent = pContent->Clone(); + } + Node::~Node() { Clear(); @@ -38,6 +45,14 @@ namespace YAML m_anchor.clear(); m_tag.clear(); } + + std::auto_ptr 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 (new Node(m_mark, m_anchor, m_tag, m_pContent)); + } void Node::Parse(Scanner *pScanner, const ParserState& state) { diff --git a/src/scalar.cpp b/src/scalar.cpp index e8146fa..a7ccda9 100644 --- a/src/scalar.cpp +++ b/src/scalar.cpp @@ -12,10 +12,19 @@ namespace YAML { } + Scalar::Scalar(const std::string& data): m_data(data) + { + } + Scalar::~Scalar() { } + Content *Scalar::Clone() const + { + return new Scalar(m_data); + } + void Scalar::Parse(Scanner *pScanner, const ParserState& /*state*/) { Token& token = pScanner->peek(); @@ -43,3 +52,4 @@ namespace YAML return 0; } } + diff --git a/src/scalar.h b/src/scalar.h index 59bcb7b..fe9a84b 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -13,8 +13,11 @@ namespace YAML { public: Scalar(); + Scalar(const std::string& data); virtual ~Scalar(); + virtual Content *Clone() const; + virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(Emitter& out) const; @@ -38,3 +41,4 @@ namespace YAML } #endif // SCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + diff --git a/src/sequence.cpp b/src/sequence.cpp index 70ca5bb..dde05c6 100644 --- a/src/sequence.cpp +++ b/src/sequence.cpp @@ -13,6 +13,12 @@ namespace YAML } + Sequence::Sequence(const std::vector& data) + { + for(std::size_t i=0;iClone().release()); + } + Sequence::~Sequence() { Clear(); @@ -25,6 +31,11 @@ namespace YAML m_data.clear(); } + Content *Sequence::Clone() const + { + return new Sequence(m_data); + } + bool Sequence::GetBegin(std::vector ::const_iterator& it) const { it = m_data.begin(); diff --git a/src/sequence.h b/src/sequence.h index f158882..fcf13dd 100644 --- a/src/sequence.h +++ b/src/sequence.h @@ -15,9 +15,12 @@ namespace YAML { public: Sequence(); + Sequence(const std::vector& data); virtual ~Sequence(); void Clear(); + virtual Content *Clone() const; + virtual bool GetBegin(std::vector ::const_iterator& it) const; virtual bool GetEnd(std::vector ::const_iterator& it) const; virtual Node *GetNode(std::size_t i) const; From c7ed85a4acf2ac9394fce22be668377235724dcc Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 24 Aug 2009 22:56:54 +0000 Subject: [PATCH 140/295] Fixed bug in anchors with no content. This involved refactoring the 'implicit sequence' concept (where a map and a sequence start on the same indent, but we read the sequence as more indented since the '-' is visually an indent). --- src/map.cpp | 4 +- src/node.cpp | 3 +- src/scanner.cpp | 75 +++++++++++++++++++++++++++++------- src/scanner.h | 18 +++++++-- src/scantoken.cpp | 18 ++++----- src/sequence.cpp | 6 +-- src/simplekey.cpp | 2 +- src/token.h | 6 ++- yaml-reader/emittertests.cpp | 10 +++++ yaml-reader/parsertests.cpp | 69 +++++++++++++++++++++++++++++++++ yaml-reader/tests.cpp | 4 ++ yaml-reader/tests.h | 4 ++ 12 files changed, 183 insertions(+), 36 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index f0038fc..ce24978 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -75,10 +75,10 @@ namespace YAML throw ParserException(Mark::null(), ErrorMsg::END_OF_MAP); Token token = pScanner->peek(); - if(token.type != TT_KEY && token.type != TT_VALUE && token.type != TT_BLOCK_END) + if(token.type != TT_KEY && token.type != TT_VALUE && token.type != TT_BLOCK_MAP_END) throw ParserException(token.mark, ErrorMsg::END_OF_MAP); - if(token.type == TT_BLOCK_END) { + if(token.type == TT_BLOCK_MAP_END) { pScanner->pop(); break; } diff --git a/src/node.cpp b/src/node.cpp index 7a460f3..7223bed 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -93,7 +93,6 @@ namespace YAML break; case TT_FLOW_SEQ_START: case TT_BLOCK_SEQ_START: - case TT_BLOCK_ENTRY: m_pContent = new Sequence; break; case TT_FLOW_MAP_START: @@ -265,7 +264,7 @@ namespace YAML // write content if(node.m_pContent) node.m_pContent->Write(out); - else + else if(!node.m_alias) out << Null; return out; diff --git a/src/scanner.cpp b/src/scanner.cpp index 5848d77..83a16fb 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -46,6 +46,7 @@ namespace YAML assert(!m_tokens.empty()); // should we be asserting here? I mean, we really just be checking // if it's empty before peeking. +// std::cerr << "peek: (" << &m_tokens.front() << ") " << m_tokens.front() << "\n"; return m_tokens.front(); } @@ -98,7 +99,7 @@ namespace YAML VerifySimpleKey(); // maybe need to end some blocks - PopIndentTo(INPUT.column()); + PopIndentToHere(); // ***** // And now branch based on the next few characters! @@ -221,7 +222,7 @@ namespace YAML { m_startedStream = true; m_simpleKeyAllowed = true; - m_indents.push(-1); + m_indents.push(IndentMarker(-1, IndentMarker::NONE)); m_anchors.clear(); } @@ -233,7 +234,7 @@ namespace YAML if(INPUT.column() > 0) INPUT.ResetColumn(); - PopIndentTo(-1); + PopAllIndents(); VerifyAllSimpleKeys(); m_simpleKeyAllowed = false; @@ -244,41 +245,87 @@ namespace YAML // . Pushes an indentation onto the stack, and enqueues the // proper token (sequence start or mapping start). // . Returns the token it generates (if any). - Token *Scanner::PushIndentTo(int column, bool sequence) + Token *Scanner::PushIndentTo(int column, IndentMarker::INDENT_TYPE type) { // are we in flow? if(m_flowLevel > 0) return 0; + + IndentMarker indent(column, type); + const IndentMarker& lastIndent = m_indents.top(); // is this actually an indentation? - if(column <= m_indents.top()) + if(indent.column < lastIndent.column) + return 0; + if(indent.column == lastIndent.column && !(indent.type == IndentMarker::SEQ && lastIndent.type == IndentMarker::MAP)) return 0; // now push - m_indents.push(column); - if(sequence) + m_indents.push(indent); + if(type == IndentMarker::SEQ) m_tokens.push(Token(TT_BLOCK_SEQ_START, INPUT.mark())); - else + else if(type == IndentMarker::MAP) m_tokens.push(Token(TT_BLOCK_MAP_START, INPUT.mark())); + else + assert(false); return &m_tokens.back(); } - // PopIndentTo - // . Pops indentations off the stack until we reach 'column' indentation, + // PopIndentToHere + // . Pops indentations off the stack until we reach the current indentation level, // and enqueues the proper token each time. - void Scanner::PopIndentTo(int column) + void Scanner::PopIndentToHere() { // are we in flow? if(m_flowLevel > 0) return; // now pop away - while(!m_indents.empty() && m_indents.top() > column) { - m_indents.pop(); - m_tokens.push(Token(TT_BLOCK_END, INPUT.mark())); + while(!m_indents.empty()) { + const IndentMarker& indent = m_indents.top(); + if(indent.column < INPUT.column()) + break; + if(indent.column == INPUT.column() && !(indent.type == IndentMarker::SEQ && !Exp::BlockEntry.Matches(INPUT))) + break; + + PopIndent(); } } + + // PopAllIndents + // . Pops all indentations off the stack, + // and enqueues the proper token each time. + void Scanner::PopAllIndents() + { + // are we in flow? + if(m_flowLevel > 0) + return; + + // now pop away + while(!m_indents.empty()) + PopIndent(); + } + + // PopIndent + // . Pops a single indent, pushing the proper token + void Scanner::PopIndent() + { + IndentMarker::INDENT_TYPE type = m_indents.top().type; + m_indents.pop(); + if(type == IndentMarker::SEQ) + m_tokens.push(Token(TT_BLOCK_SEQ_END, INPUT.mark())); + else if(type == IndentMarker::MAP) + m_tokens.push(Token(TT_BLOCK_MAP_END, INPUT.mark())); + } + + // GetTopIndent + int Scanner::GetTopIndent() const + { + if(m_indents.empty()) + return 0; + return m_indents.top().column; + } // Save // . Saves a pointer to the Node object referenced by a particular anchor diff --git a/src/scanner.h b/src/scanner.h index 36aa917..853fa64 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -34,14 +34,26 @@ namespace YAML void ClearAnchors(); private: + struct IndentMarker { + enum INDENT_TYPE { MAP, SEQ, NONE }; + IndentMarker(int column_, INDENT_TYPE type_): column(column_), type(type_) {} + + int column; + INDENT_TYPE type; + }; + + private: // scanning void EnsureTokensInQueue(); void ScanNextToken(); void ScanToNextToken(); void StartStream(); void EndStream(); - Token *PushIndentTo(int column, bool sequence); - void PopIndentTo(int column); + Token *PushIndentTo(int column, IndentMarker::INDENT_TYPE type); + void PopIndentToHere(); + void PopAllIndents(); + void PopIndent(); + int GetTopIndent() const; // checking input void InsertSimpleKey(); @@ -94,7 +106,7 @@ namespace YAML int m_flowLevel; // number of unclosed '[' and '{' indicators bool m_isLastKeyValid; std::stack m_simpleKeys; - std::stack m_indents; + std::stack m_indents; std::map m_anchors; }; } diff --git a/src/scantoken.cpp b/src/scantoken.cpp index 3699b4d..22b9712 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -19,7 +19,7 @@ namespace YAML std::vector params; // pop indents and simple keys - PopIndentTo(-1); + PopAllIndents(); VerifyAllSimpleKeys(); m_simpleKeyAllowed = false; @@ -59,7 +59,7 @@ namespace YAML // DocStart void Scanner::ScanDocStart() { - PopIndentTo(-1); + PopAllIndents(); VerifyAllSimpleKeys(); m_simpleKeyAllowed = false; @@ -72,7 +72,7 @@ namespace YAML // DocEnd void Scanner::ScanDocEnd() { - PopIndentTo(-1); + PopAllIndents(); VerifyAllSimpleKeys(); m_simpleKeyAllowed = false; @@ -135,7 +135,7 @@ namespace YAML if(!m_simpleKeyAllowed) throw ParserException(INPUT.mark(), ErrorMsg::BLOCK_ENTRY); - PushIndentTo(INPUT.column(), true); + PushIndentTo(INPUT.column(), IndentMarker::SEQ); m_simpleKeyAllowed = true; // eat @@ -152,7 +152,7 @@ namespace YAML if(!m_simpleKeyAllowed) throw ParserException(INPUT.mark(), ErrorMsg::MAP_KEY); - PushIndentTo(INPUT.column(), false); + PushIndentTo(INPUT.column(), IndentMarker::MAP); } // can only put a simple key here if we're in block context @@ -180,7 +180,7 @@ namespace YAML if(!m_simpleKeyAllowed) throw ParserException(INPUT.mark(), ErrorMsg::MAP_VALUE); - PushIndentTo(INPUT.column(), false); + PushIndentTo(INPUT.column(), IndentMarker::MAP); } // can only put a simple key here if we're in block context @@ -277,7 +277,7 @@ namespace YAML ScanScalarParams params; params.end = (m_flowLevel > 0 ? Exp::EndScalarInFlow : Exp::EndScalar) || (Exp::BlankOrBreak + Exp::Comment); params.eatEnd = false; - params.indent = (m_flowLevel > 0 ? 0 : m_indents.top() + 1); + params.indent = (m_flowLevel > 0 ? 0 : GetTopIndent() + 1); params.fold = true; params.eatLeadingWhitespace = true; params.trimTrailingSpaces = true; @@ -391,8 +391,8 @@ namespace YAML throw ParserException(INPUT.mark(), ErrorMsg::CHAR_IN_BLOCK); // set the initial indentation - if(m_indents.top() >= 0) - params.indent += m_indents.top(); + if(GetTopIndent() >= 0) + params.indent += GetTopIndent(); params.eatLeadingWhitespace = false; params.trimTrailingSpaces = false; diff --git a/src/sequence.cpp b/src/sequence.cpp index dde05c6..5073f08 100644 --- a/src/sequence.cpp +++ b/src/sequence.cpp @@ -83,11 +83,11 @@ namespace YAML throw ParserException(Mark::null(), ErrorMsg::END_OF_SEQ); Token token = pScanner->peek(); - if(token.type != TT_BLOCK_ENTRY && token.type != TT_BLOCK_END) + if(token.type != TT_BLOCK_ENTRY && token.type != TT_BLOCK_SEQ_END) throw ParserException(token.mark, ErrorMsg::END_OF_SEQ); pScanner->pop(); - if(token.type == TT_BLOCK_END) + if(token.type == TT_BLOCK_SEQ_END) break; Node *pNode = new Node; @@ -96,7 +96,7 @@ namespace YAML // check for null if(!pScanner->empty()) { const Token& token = pScanner->peek(); - if(token.type == TT_BLOCK_ENTRY || token.type == TT_BLOCK_END) + if(token.type == TT_BLOCK_ENTRY || token.type == TT_BLOCK_SEQ_END) continue; } diff --git a/src/simplekey.cpp b/src/simplekey.cpp index f1c0a2b..85dc7f8 100644 --- a/src/simplekey.cpp +++ b/src/simplekey.cpp @@ -35,7 +35,7 @@ namespace YAML SimpleKey key(INPUT.mark(), m_flowLevel); // first add a map start, if necessary - key.pMapStart = PushIndentTo(INPUT.column(), false); + key.pMapStart = PushIndentTo(INPUT.column(), IndentMarker::MAP); if(key.pMapStart) key.pMapStart->status = TS_UNVERIFIED; diff --git a/src/token.h b/src/token.h index 060861a..c21524d 100644 --- a/src/token.h +++ b/src/token.h @@ -18,7 +18,8 @@ namespace YAML TT_DOC_END, TT_BLOCK_SEQ_START, TT_BLOCK_MAP_START, - TT_BLOCK_END, + TT_BLOCK_SEQ_END, + TT_BLOCK_MAP_END, TT_BLOCK_ENTRY, TT_FLOW_SEQ_START, TT_FLOW_MAP_START, @@ -39,7 +40,8 @@ namespace YAML "DOC_END", "BLOCK_SEQ_START", "BLOCK_MAP_START", - "BLOCK_END", + "BLOCK_SEQ_END", + "BLOCK_MAP_END", "BLOCK_ENTRY", "FLOW_SEQ_START", "FLOW_MAP_START", diff --git a/yaml-reader/emittertests.cpp b/yaml-reader/emittertests.cpp index a016bff..95c0ac4 100644 --- a/yaml-reader/emittertests.cpp +++ b/yaml-reader/emittertests.cpp @@ -272,6 +272,16 @@ namespace Test desiredOutput = "- &fred\n name: Fred\n age: 42\n- *fred"; } + void AliasAndAnchorWithNull(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << YAML::Anchor("fred") << YAML::Null; + out << YAML::Alias("fred"); + out << YAML::EndSeq; + + desiredOutput = "- &fred ~\n- *fred"; + } + void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput) { out << YAML::BeginMap; diff --git a/yaml-reader/parsertests.cpp b/yaml-reader/parsertests.cpp index 3b2e28d..03c833e 100644 --- a/yaml-reader/parsertests.cpp +++ b/yaml-reader/parsertests.cpp @@ -248,6 +248,30 @@ namespace Test return true; } + bool CompressedMapAndSeq() + { + std::string input = "key:\n- one\n- two"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + const YAML::Node& seq = doc["key"]; + if(seq.size() != 2) + return false; + + std::string output; + seq[0] >> output; + if(output != "one") + return false; + seq[1] >> output; + if(output != "two") + return false; + + return true; + } + bool NullBlockSeqEntry() { std::string input = "- hello\n-\n- world"; @@ -301,5 +325,50 @@ namespace Test return true; } + + bool SimpleAlias() + { + std::string input = "- &alias test\n- *alias"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc[0] >> output; + if(output != "test") + return false; + + doc[1] >> output; + if(output != "test") + return false; + + if(doc.size() != 2) + return false; + + return true; + } + + bool AliasWithNull() + { + std::string input = "- &alias\n- *alias"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + if(!IsNull(doc[0])) + return false; + + if(!IsNull(doc[1])) + return false; + + if(doc.size() != 2) + return false; + + return true; + } } } diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp index f434c03..00c5132 100644 --- a/yaml-reader/tests.cpp +++ b/yaml-reader/tests.cpp @@ -263,9 +263,12 @@ namespace Test RunParserTest(&Parser::FlowSeq, "flow seq", passed); RunParserTest(&Parser::FlowMap, "flow map", passed); RunParserTest(&Parser::QuotedSimpleKeys, "quoted simple keys", passed); + RunParserTest(&Parser::CompressedMapAndSeq, "compressed map and seq", passed); RunParserTest(&Parser::NullBlockSeqEntry, "null block seq entry", passed); RunParserTest(&Parser::NullBlockMapKey, "null block map key", passed); RunParserTest(&Parser::NullBlockMapValue, "null block map value", passed); + RunParserTest(&Parser::SimpleAlias, "simple alias", passed); + RunParserTest(&Parser::AliasWithNull, "alias with null", passed); RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed); RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed); @@ -346,6 +349,7 @@ namespace Test RunEmitterTest(&Emitter::LongKeyFlowMap, "long key flow map", passed); RunEmitterTest(&Emitter::BlockMapAsKey, "block map as key", passed); RunEmitterTest(&Emitter::AliasAndAnchor, "alias and anchor", passed); + RunEmitterTest(&Emitter::AliasAndAnchorWithNull, "alias and anchor with null", passed); RunEmitterTest(&Emitter::ComplexDoc, "complex doc", passed); RunEmitterTest(&Emitter::STLContainers, "STL containers", passed); RunEmitterTest(&Emitter::SimpleComment, "simple comment", passed); diff --git a/yaml-reader/tests.h b/yaml-reader/tests.h index e205166..f8b3205 100644 --- a/yaml-reader/tests.h +++ b/yaml-reader/tests.h @@ -34,9 +34,12 @@ namespace Test { bool FlowSeq(); bool FlowMap(); bool QuotedSimpleKeys(); + bool CompressedMapAndSeq(); bool NullBlockSeqEntry(); bool NullBlockMapKey(); bool NullBlockMapValue(); + bool SimpleAlias(); + bool AliasWithNull(); } namespace Emitter { @@ -63,6 +66,7 @@ namespace Test { void LongKeyFlowMap(YAML::Emitter& out, std::string& desiredOutput); void BlockMapAsKey(YAML::Emitter& out, std::string& desiredOutput); void AliasAndAnchor(YAML::Emitter& out, std::string& desiredOutput); + void AliasAndAnchorWithNull(YAML::Emitter& out, std::string& desiredOutput); void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput); void STLContainers(YAML::Emitter& out, std::string& desiredOutput); void SimpleComment(YAML::Emitter& out, std::string& desiredOutput); From 4457b7dd5b1fcc8c6db21c0c017097520b90bd38 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 24 Aug 2009 22:58:47 +0000 Subject: [PATCH 141/295] Removed the implicit sequence code (since it's not used any more) --- src/sequence.cpp | 21 --------------------- src/sequence.h | 1 - 2 files changed, 22 deletions(-) diff --git a/src/sequence.cpp b/src/sequence.cpp index 5073f08..31c88e1 100644 --- a/src/sequence.cpp +++ b/src/sequence.cpp @@ -67,7 +67,6 @@ namespace YAML // split based on start token switch(pScanner->peek().type) { case TT_BLOCK_SEQ_START: ParseBlock(pScanner, state); break; - case TT_BLOCK_ENTRY: ParseImplicit(pScanner, state); break; case TT_FLOW_SEQ_START: ParseFlow(pScanner, state); break; default: break; } @@ -104,26 +103,6 @@ namespace YAML } } - void Sequence::ParseImplicit(Scanner *pScanner, const ParserState& state) - { - while(1) { - // we're actually *allowed* to have no tokens at some point - if(pScanner->empty()) - break; - - // and we end at anything other than a block entry - Token& token = pScanner->peek(); - if(token.type != TT_BLOCK_ENTRY) - break; - - pScanner->pop(); - - Node *pNode = new Node; - m_data.push_back(pNode); - pNode->Parse(pScanner, state); - } - } - void Sequence::ParseFlow(Scanner *pScanner, const ParserState& state) { // eat start token diff --git a/src/sequence.h b/src/sequence.h index fcf13dd..ad4fde5 100644 --- a/src/sequence.h +++ b/src/sequence.h @@ -39,7 +39,6 @@ namespace YAML private: void ParseBlock(Scanner *pScanner, const ParserState& state); - void ParseImplicit(Scanner *pScanner, const ParserState& state); void ParseFlow(Scanner *pScanner, const ParserState& state); protected: From 3c35ab1e4248882c37c41b01431aec1124e84752 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 24 Aug 2009 23:43:53 +0000 Subject: [PATCH 142/295] Added CMake option to build for the iphone --- CMakeLists.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e71963d..7ea3e2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,13 @@ cmake_minimum_required(VERSION 2.6) project (YAML_CPP) +set(LIB_TYPE SHARED) + +if(IPHONE) + set(CMAKE_OSX_SYSROOT iphoneos2.2.1) + set(LIB_TYPE) +endif(IPHONE) + if(CMAKE_COMPILER_IS_GNUCC) set(CMAKE_CXX_FLAGS "-O2 -Wall -pedantic -Wextra") endif(CMAKE_COMPILER_IS_GNUCC) @@ -34,7 +41,8 @@ file(GLOB private_headers src/*.h) file(GLOB sources src/*.cpp) include_directories(${YAML_CPP_SOURCE_DIR}/include) -add_library(yaml-cpp SHARED +add_library(yaml-cpp + ${LIB_TYPE} ${public_headers} ${private_headers} ${sources} From aadc5052bce66b58d1763064f0b74fb88faea0f0 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 26 Aug 2009 16:15:27 +0000 Subject: [PATCH 143/295] Fixed bug with explicit doc start introduced in last commit --- src/scanner.cpp | 9 +++++-- yaml-reader/parsertests.cpp | 48 +++++++++++++++++++++++++++++++++++++ yaml-reader/tests.cpp | 2 ++ yaml-reader/tests.h | 2 ++ 4 files changed, 59 insertions(+), 2 deletions(-) diff --git a/src/scanner.cpp b/src/scanner.cpp index 83a16fb..7429084 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -294,7 +294,7 @@ namespace YAML } // PopAllIndents - // . Pops all indentations off the stack, + // . Pops all indentations (except for the base empty one) off the stack, // and enqueues the proper token each time. void Scanner::PopAllIndents() { @@ -303,8 +303,13 @@ namespace YAML return; // now pop away - while(!m_indents.empty()) + while(!m_indents.empty()) { + const IndentMarker& indent = m_indents.top(); + if(indent.type == IndentMarker::NONE) + break; + PopIndent(); + } } // PopIndent diff --git a/yaml-reader/parsertests.cpp b/yaml-reader/parsertests.cpp index 03c833e..d0342e2 100644 --- a/yaml-reader/parsertests.cpp +++ b/yaml-reader/parsertests.cpp @@ -370,5 +370,53 @@ namespace Test return true; } + + bool ExplicitDoc() + { + std::string input = "---\n- one\n- two"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + if(doc.size() != 2) + return false; + + std::string output; + doc[0] >> output; + if(output != "one") + return false; + doc[1] >> output; + if(output != "two") + return false; + + return true; + } + + bool MultipleDocs() + { + std::string input = "---\nname: doc1\n---\nname: doc2"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc["name"] >> output; + if(output != "doc1") + return false; + + if(!parser) + return false; + + parser.GetNextDocument(doc); + doc["name"] >> output; + if(output != "doc2") + return false; + + return true; + } } } diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp index 00c5132..9796b63 100644 --- a/yaml-reader/tests.cpp +++ b/yaml-reader/tests.cpp @@ -269,6 +269,8 @@ namespace Test RunParserTest(&Parser::NullBlockMapValue, "null block map value", passed); RunParserTest(&Parser::SimpleAlias, "simple alias", passed); RunParserTest(&Parser::AliasWithNull, "alias with null", passed); + RunParserTest(&Parser::ExplicitDoc, "explicit doc", passed); + RunParserTest(&Parser::MultipleDocs, "multiple docs", passed); RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed); RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed); diff --git a/yaml-reader/tests.h b/yaml-reader/tests.h index f8b3205..91f7def 100644 --- a/yaml-reader/tests.h +++ b/yaml-reader/tests.h @@ -40,6 +40,8 @@ namespace Test { bool NullBlockMapValue(); bool SimpleAlias(); bool AliasWithNull(); + bool ExplicitDoc(); + bool MultipleDocs(); } namespace Emitter { From 2e859413e70b3b9a7d1402874d0962ea10755145 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 26 Aug 2009 16:23:58 +0000 Subject: [PATCH 144/295] Added more explicit doc indicator tests --- yaml-reader/parsertests.cpp | 69 +++++++++++++++++++++++++++++++++++++ yaml-reader/tests.cpp | 2 ++ yaml-reader/tests.h | 2 ++ 3 files changed, 73 insertions(+) diff --git a/yaml-reader/parsertests.cpp b/yaml-reader/parsertests.cpp index d0342e2..3fbc457 100644 --- a/yaml-reader/parsertests.cpp +++ b/yaml-reader/parsertests.cpp @@ -418,5 +418,74 @@ namespace Test return true; } + + bool ExplicitEndDoc() + { + std::string input = "- one\n- two\n...\n..."; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + if(doc.size() != 2) + return false; + + std::string output; + doc[0] >> output; + if(output != "one") + return false; + doc[1] >> output; + if(output != "two") + return false; + + return true; + } + + bool MultipleDocsWithSomeExplicitIndicators() + { + std::string input = + "- one\n- two\n...\n" + "---\nkey: value\n...\n...\n" + "- three\n- four\n" + "---\nkey: value"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + std::string output; + + parser.GetNextDocument(doc); + if(doc.size() != 2) + return false; + doc[0] >> output; + if(output != "one") + return false; + doc[1] >> output; + if(output != "two") + return false; + + parser.GetNextDocument(doc); + doc["key"] >> output; + if(output != "value") + return false; + + parser.GetNextDocument(doc); + if(doc.size() != 2) + return false; + doc[0] >> output; + if(output != "three") + return false; + doc[1] >> output; + if(output != "four") + return false; + + parser.GetNextDocument(doc); + doc["key"] >> output; + if(output != "value") + return false; + + return true; + } } } diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp index 9796b63..5193a90 100644 --- a/yaml-reader/tests.cpp +++ b/yaml-reader/tests.cpp @@ -271,6 +271,8 @@ namespace Test RunParserTest(&Parser::AliasWithNull, "alias with null", passed); RunParserTest(&Parser::ExplicitDoc, "explicit doc", passed); RunParserTest(&Parser::MultipleDocs, "multiple docs", passed); + RunParserTest(&Parser::ExplicitEndDoc, "explicit end doc", passed); + RunParserTest(&Parser::MultipleDocsWithSomeExplicitIndicators, "multiple docs with some explicit indicators", passed); RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed); RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed); diff --git a/yaml-reader/tests.h b/yaml-reader/tests.h index 91f7def..67e6361 100644 --- a/yaml-reader/tests.h +++ b/yaml-reader/tests.h @@ -42,6 +42,8 @@ namespace Test { bool AliasWithNull(); bool ExplicitDoc(); bool MultipleDocs(); + bool ExplicitEndDoc(); + bool MultipleDocsWithSomeExplicitIndicators(); } namespace Emitter { From f7a47e9f9f196b240f081d064d88b35cfcb7e13f Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 2 Sep 2009 21:39:57 +0000 Subject: [PATCH 145/295] Fixed bug with omitted keys/values in a flow map --- src/exp.h | 4 ++-- src/scanner.cpp | 2 +- src/scantoken.cpp | 6 ++++++ yaml-reader/parsertests.cpp | 36 ++++++++++++++++++++++++++++++++++++ yaml-reader/tests.cpp | 2 ++ yaml-reader/tests.h | 2 ++ 6 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/exp.h b/src/exp.h index 1b5ac74..e7a96b5 100644 --- a/src/exp.h +++ b/src/exp.h @@ -37,7 +37,7 @@ namespace YAML const RegEx Key = RegEx('?'), KeyInFlow = RegEx('?') + BlankOrBreak; const RegEx Value = RegEx(':') + (BlankOrBreak || RegEx()), - ValueInFlow = RegEx(':') + BlankOrBreak; + ValueInFlow = RegEx(':') + (BlankOrBreak || RegEx(",}", REGEX_OR)); const RegEx Comment = RegEx('#'); const RegEx AnchorEnd = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak; @@ -49,7 +49,7 @@ namespace YAML const RegEx PlainScalar = !(BlankOrBreak || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:", REGEX_OR) + Blank)), PlainScalarInFlow = !(BlankOrBreak || RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-:", REGEX_OR) + Blank)); const RegEx EndScalar = RegEx(':') + (BlankOrBreak || RegEx()), - EndScalarInFlow = (RegEx(':') + BlankOrBreak) || RegEx(",?[]{}", REGEX_OR); + EndScalarInFlow = (RegEx(':') + (BlankOrBreak || RegEx(",]}", REGEX_OR))) || RegEx(",?[]{}", REGEX_OR); const RegEx EscSingleQuote = RegEx("\'\'"); const RegEx EscBreak = RegEx('\\') + Break; diff --git a/src/scanner.cpp b/src/scanner.cpp index 7429084..407abf2 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -104,7 +104,7 @@ namespace YAML // ***** // And now branch based on the next few characters! // ***** - + // end of stream if(!INPUT) return EndStream(); diff --git a/src/scantoken.cpp b/src/scantoken.cpp index 22b9712..9f1fda1 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -181,6 +181,12 @@ namespace YAML throw ParserException(INPUT.mark(), ErrorMsg::MAP_VALUE); PushIndentTo(INPUT.column(), IndentMarker::MAP); + } else { + // we might have an empty key, so we should add it (as a simple key) + if(m_simpleKeyAllowed) { + InsertSimpleKey(); + VerifySimpleKey(); + } } // can only put a simple key here if we're in block context diff --git a/yaml-reader/parsertests.cpp b/yaml-reader/parsertests.cpp index 3fbc457..e3410df 100644 --- a/yaml-reader/parsertests.cpp +++ b/yaml-reader/parsertests.cpp @@ -220,6 +220,42 @@ namespace Test return true; } + bool FlowMapWithOmittedKey() + { + std::string input = "{: omitted key}"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc[YAML::Null] >> output; + if(output != "omitted key") + return false; + + return true; + } + + bool FlowMapWithOmittedValue() + { + std::string input = "{a: b, c:, d:}"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc["a"] >> output; + if(output != "b") + return false; + if(!IsNull(doc["c"])) + return false; + if(!IsNull(doc["d"])) + return false; + + return true; + } + bool QuotedSimpleKeys() { std::string KeyValue[3] = { "\"double\": double\n", "'single': single\n", "plain: plain\n" }; diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp index 5193a90..89d7c20 100644 --- a/yaml-reader/tests.cpp +++ b/yaml-reader/tests.cpp @@ -262,6 +262,8 @@ namespace Test RunParserTest(&Parser::SimpleMap, "simple map", passed); RunParserTest(&Parser::FlowSeq, "flow seq", passed); RunParserTest(&Parser::FlowMap, "flow map", passed); + RunParserTest(&Parser::FlowMapWithOmittedKey, "flow map with omitted key", passed); + RunParserTest(&Parser::FlowMapWithOmittedValue, "flow map with omitted value", passed); RunParserTest(&Parser::QuotedSimpleKeys, "quoted simple keys", passed); RunParserTest(&Parser::CompressedMapAndSeq, "compressed map and seq", passed); RunParserTest(&Parser::NullBlockSeqEntry, "null block seq entry", passed); diff --git a/yaml-reader/tests.h b/yaml-reader/tests.h index 67e6361..9aa9578 100644 --- a/yaml-reader/tests.h +++ b/yaml-reader/tests.h @@ -33,6 +33,8 @@ namespace Test { bool SimpleMap(); bool FlowSeq(); bool FlowMap(); + bool FlowMapWithOmittedKey(); + bool FlowMapWithOmittedValue(); bool QuotedSimpleKeys(); bool CompressedMapAndSeq(); bool NullBlockSeqEntry(); From a926fefe0dbe201edc1199e0d7f1d2cfd9a52783 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 3 Sep 2009 14:27:03 +0000 Subject: [PATCH 146/295] Started implementing spec tests --- yaml-reader/spectests.cpp | 91 +++++++++++++++++++++++++++++++++++++++ yaml-reader/spectests.h | 11 +++++ yaml-reader/tests.cpp | 6 ++- 3 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 yaml-reader/spectests.cpp create mode 100644 yaml-reader/spectests.h diff --git a/yaml-reader/spectests.cpp b/yaml-reader/spectests.cpp new file mode 100644 index 0000000..3169b43 --- /dev/null +++ b/yaml-reader/spectests.cpp @@ -0,0 +1,91 @@ +#include "spectests.h" +#include "yaml.h" +#include +#include +#include +#include + +namespace Test { + namespace { + void RunSpecTest(bool (*test)(), const std::string& index, const std::string& name, bool& passed) { + std::string error; + bool ok = true; + try { + ok = test(); + } catch(const YAML::Exception& e) { + ok = false; + error = e.msg; + } + if(ok) { + std::cout << "Spec test " << index << " passed: " << name << "\n"; + } else { + passed = false; + std::cout << "Spec test " << index << " failed: " << name << "\n"; + if(error != "") + std::cout << "Caught exception: " << error << "\n"; + } + } + } + + namespace Spec { + bool SeqScalars() { + std::string input = + "- Mark McGwire\n" + "- Sammy Sosa\n" + "- Ken Griffey"; + std::stringstream stream(input); + + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + if(doc.size() != 3) + return false; + std::string output; + doc[0] >> output; + if(output != "Mark McGwire") + return false; + doc[1] >> output; + if(output != "Sammy Sosa") + return false; + doc[2] >> output; + if(output != "Ken Griffey") + return false; + return true; + } + + bool MappingScalarsToScalars() { + std::string input = + "hr: 65 # Home runs\n" + "avg: 0.278 # Batting average\n" + "rbi: 147 # Runs Batted In"; + std::stringstream stream(input); + + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc["hr"] >> output; + if(output != "65") + return false; + doc["avg"] >> output; + if(output != "0.278") + return false; + doc["rbi"] >> output; + if(output != "147") + return false; + return true; + } + } + + bool RunSpecTests() + { + bool passed = true; + RunSpecTest(&Spec::SeqScalars, "2.1", "Sequence of Scalars", passed); + RunSpecTest(&Spec::MappingScalarsToScalars, "2.2", "Mapping Scalars to Scalars", passed); + return passed; + } + +} + diff --git a/yaml-reader/spectests.h b/yaml-reader/spectests.h new file mode 100644 index 0000000..fcb1fb4 --- /dev/null +++ b/yaml-reader/spectests.h @@ -0,0 +1,11 @@ +#pragma once + +#ifndef SPECTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define SPECTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +namespace Test { + bool RunSpecTests(); +} + +#endif // SPECTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp index 89d7c20..8bf33ba 100644 --- a/yaml-reader/tests.cpp +++ b/yaml-reader/tests.cpp @@ -1,5 +1,6 @@ -#include "yaml.h" #include "tests.h" +#include "spectests.h" +#include "yaml.h" #include #include #include @@ -12,6 +13,9 @@ namespace Test bool passed = true; if(!RunParserTests()) passed = false; + + if(!RunSpecTests()) + passed = false; if(!RunEmitterTests()) passed = false; From 6594941d24a3fa2b38ebe6539da53c0fc1391373 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sat, 5 Sep 2009 02:28:11 +0000 Subject: [PATCH 147/295] Moved token enums into Token scope --- src/map.cpp | 22 +++++++++---------- src/node.cpp | 16 +++++++------- src/parser.cpp | 6 +++--- src/scanner.cpp | 14 ++++++------ src/scantoken.cpp | 28 ++++++++++++------------ src/sequence.cpp | 16 +++++++------- src/simplekey.cpp | 14 ++++++------ src/token.h | 54 ++++++++++++++++++++++++----------------------- 8 files changed, 86 insertions(+), 84 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index ce24978..8aadec9 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -59,8 +59,8 @@ namespace YAML // split based on start token switch(pScanner->peek().type) { - case TT_BLOCK_MAP_START: ParseBlock(pScanner, state); break; - case TT_FLOW_MAP_START: ParseFlow(pScanner, state); break; + case Token::BLOCK_MAP_START: ParseBlock(pScanner, state); break; + case Token::FLOW_MAP_START: ParseFlow(pScanner, state); break; default: break; } } @@ -75,10 +75,10 @@ namespace YAML throw ParserException(Mark::null(), ErrorMsg::END_OF_MAP); Token token = pScanner->peek(); - if(token.type != TT_KEY && token.type != TT_VALUE && token.type != TT_BLOCK_MAP_END) + 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 == TT_BLOCK_MAP_END) { + if(token.type == Token::BLOCK_MAP_END) { pScanner->pop(); break; } @@ -86,13 +86,13 @@ namespace YAML std::auto_ptr pKey(new Node), pValue(new Node); // grab key (if non-null) - if(token.type == TT_KEY) { + if(token.type == Token::KEY) { pScanner->pop(); pKey->Parse(pScanner, state); } // now grab value (optional) - if(!pScanner->empty() && pScanner->peek().type == TT_VALUE) { + if(!pScanner->empty() && pScanner->peek().type == Token::VALUE) { pScanner->pop(); pValue->Parse(pScanner, state); } @@ -113,13 +113,13 @@ namespace YAML Token& token = pScanner->peek(); // first check for end - if(token.type == TT_FLOW_MAP_END) { + if(token.type == Token::FLOW_MAP_END) { pScanner->pop(); break; } // now it better be a key - if(token.type != TT_KEY) + if(token.type != Token::KEY) throw ParserException(token.mark, ErrorMsg::END_OF_MAP_FLOW); pScanner->pop(); @@ -130,16 +130,16 @@ namespace YAML pKey->Parse(pScanner, state); // now grab value (optional) - if(!pScanner->empty() && pScanner->peek().type == TT_VALUE) { + 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 == TT_FLOW_ENTRY) + if(nextToken.type == Token::FLOW_ENTRY) pScanner->pop(); - else if(nextToken.type != TT_FLOW_MAP_END) + else if(nextToken.type != Token::FLOW_MAP_END) throw ParserException(nextToken.mark, ErrorMsg::END_OF_MAP_FLOW); // assign the map with the actual pointers diff --git a/src/node.cpp b/src/node.cpp index 7223bed..c604e43 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -88,15 +88,15 @@ namespace YAML // now split based on what kind of node we should be switch(pScanner->peek().type) { - case TT_SCALAR: + case Token::SCALAR: m_pContent = new Scalar; break; - case TT_FLOW_SEQ_START: - case TT_BLOCK_SEQ_START: + case Token::FLOW_SEQ_START: + case Token::BLOCK_SEQ_START: m_pContent = new Sequence; break; - case TT_FLOW_MAP_START: - case TT_BLOCK_MAP_START: + case Token::FLOW_MAP_START: + case Token::BLOCK_MAP_START: m_pContent = new Map; break; default: @@ -124,9 +124,9 @@ namespace YAML return; switch(pScanner->peek().type) { - case TT_TAG: ParseTag(pScanner, state); break; - case TT_ANCHOR: ParseAnchor(pScanner, state); break; - case TT_ALIAS: ParseAlias(pScanner, state); break; + case Token::TAG: ParseTag(pScanner, state); break; + case Token::ANCHOR: ParseAnchor(pScanner, state); break; + case Token::ALIAS: ParseAlias(pScanner, state); break; default: return; } } diff --git a/src/parser.cpp b/src/parser.cpp index e3b088b..162364f 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -46,14 +46,14 @@ namespace YAML return; // first eat doc start (optional) - if(m_pScanner->peek().type == TT_DOC_START) + if(m_pScanner->peek().type == Token::DOC_START) m_pScanner->pop(); // now parse our root node document.Parse(m_pScanner, m_state); // and finally eat any doc ends we see - while(!m_pScanner->empty() && m_pScanner->peek().type == TT_DOC_END) + while(!m_pScanner->empty() && m_pScanner->peek().type == Token::DOC_END) m_pScanner->pop(); // clear anchors from the scanner, which are no longer relevant @@ -71,7 +71,7 @@ namespace YAML break; Token& token = m_pScanner->peek(); - if(token.type != TT_DIRECTIVE) + if(token.type != Token::DIRECTIVE) break; // we keep the directives from the last document if none are specified; diff --git a/src/scanner.cpp b/src/scanner.cpp index 407abf2..988ed43 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -31,7 +31,7 @@ namespace YAML EnsureTokensInQueue(); if(!m_tokens.empty()) { // Saved anchors shouldn't survive popping the document end marker - if (m_tokens.front().type == TT_DOC_END) { + if (m_tokens.front().type == Token::DOC_END) { ClearAnchors(); } m_tokens.pop(); @@ -60,11 +60,11 @@ namespace YAML Token& token = m_tokens.front(); // if this guy's valid, then we're done - if(token.status == TS_VALID) + if(token.status == Token::VALID) return; // here's where we clean up the impossible tokens - if(token.status == TS_INVALID) { + if(token.status == Token::INVALID) { m_tokens.pop(); continue; } @@ -263,9 +263,9 @@ namespace YAML // now push m_indents.push(indent); if(type == IndentMarker::SEQ) - m_tokens.push(Token(TT_BLOCK_SEQ_START, INPUT.mark())); + m_tokens.push(Token(Token::BLOCK_SEQ_START, INPUT.mark())); else if(type == IndentMarker::MAP) - m_tokens.push(Token(TT_BLOCK_MAP_START, INPUT.mark())); + m_tokens.push(Token(Token::BLOCK_MAP_START, INPUT.mark())); else assert(false); @@ -319,9 +319,9 @@ namespace YAML IndentMarker::INDENT_TYPE type = m_indents.top().type; m_indents.pop(); if(type == IndentMarker::SEQ) - m_tokens.push(Token(TT_BLOCK_SEQ_END, INPUT.mark())); + m_tokens.push(Token(Token::BLOCK_SEQ_END, INPUT.mark())); else if(type == IndentMarker::MAP) - m_tokens.push(Token(TT_BLOCK_MAP_END, INPUT.mark())); + m_tokens.push(Token(Token::BLOCK_MAP_END, INPUT.mark())); } // GetTopIndent diff --git a/src/scantoken.cpp b/src/scantoken.cpp index 9f1fda1..fa853f7 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -50,7 +50,7 @@ namespace YAML params.push_back(param); } - Token token(TT_DIRECTIVE, mark); + Token token(Token::DIRECTIVE, mark); token.value = name; token.params = params; m_tokens.push(token); @@ -66,7 +66,7 @@ namespace YAML // eat Mark mark = INPUT.mark(); INPUT.eat(3); - m_tokens.push(Token(TT_DOC_START, mark)); + m_tokens.push(Token(Token::DOC_START, mark)); } // DocEnd @@ -79,7 +79,7 @@ namespace YAML // eat Mark mark = INPUT.mark(); INPUT.eat(3); - m_tokens.push(Token(TT_DOC_END, mark)); + m_tokens.push(Token(Token::DOC_END, mark)); } // FlowStart @@ -93,7 +93,7 @@ namespace YAML // eat Mark mark = INPUT.mark(); char ch = INPUT.get(); - TOKEN_TYPE type = (ch == Keys::FlowSeqStart ? TT_FLOW_SEQ_START : TT_FLOW_MAP_START); + Token::TYPE type = (ch == Keys::FlowSeqStart ? Token::FLOW_SEQ_START : Token::FLOW_MAP_START); m_tokens.push(Token(type, mark)); } @@ -109,7 +109,7 @@ namespace YAML // eat Mark mark = INPUT.mark(); char ch = INPUT.get(); - TOKEN_TYPE type = (ch == Keys::FlowSeqEnd ? TT_FLOW_SEQ_END : TT_FLOW_MAP_END); + Token::TYPE type = (ch == Keys::FlowSeqEnd ? Token::FLOW_SEQ_END : Token::FLOW_MAP_END); m_tokens.push(Token(type, mark)); } @@ -121,7 +121,7 @@ namespace YAML // eat Mark mark = INPUT.mark(); INPUT.eat(1); - m_tokens.push(Token(TT_FLOW_ENTRY, mark)); + m_tokens.push(Token(Token::FLOW_ENTRY, mark)); } // BlockEntry @@ -141,7 +141,7 @@ namespace YAML // eat Mark mark = INPUT.mark(); INPUT.eat(1); - m_tokens.push(Token(TT_BLOCK_ENTRY, mark)); + m_tokens.push(Token(Token::BLOCK_ENTRY, mark)); } // Key @@ -164,7 +164,7 @@ namespace YAML // eat Mark mark = INPUT.mark(); INPUT.eat(1); - m_tokens.push(Token(TT_KEY, mark)); + m_tokens.push(Token(Token::KEY, mark)); } // Value @@ -199,7 +199,7 @@ namespace YAML // eat Mark mark = INPUT.mark(); INPUT.eat(1); - m_tokens.push(Token(TT_VALUE, mark)); + m_tokens.push(Token(Token::VALUE, mark)); } // AnchorOrAlias @@ -231,7 +231,7 @@ namespace YAML throw ParserException(INPUT.mark(), alias ? ErrorMsg::CHAR_IN_ALIAS : ErrorMsg::CHAR_IN_ANCHOR); // and we're done - Token token(alias ? TT_ALIAS : TT_ANCHOR, mark); + Token token(alias ? Token::ALIAS : Token::ANCHOR, mark); token.value = name; m_tokens.push(token); } @@ -268,7 +268,7 @@ namespace YAML handle = "!"; } - Token token(TT_TAG, mark); + Token token(Token::TAG, mark); token.value = handle; token.params.push_back(suffix); m_tokens.push(token); @@ -305,7 +305,7 @@ namespace YAML //if(Exp::IllegalCharInScalar.Matches(INPUT)) // throw ParserException(INPUT.mark(), ErrorMsg::CHAR_IN_SCALAR); - Token token(TT_SCALAR, mark); + Token token(Token::SCALAR, mark); token.value = scalar; m_tokens.push(token); } @@ -344,7 +344,7 @@ namespace YAML scalar = ScanScalar(INPUT, params); m_simpleKeyAllowed = false; - Token token(TT_SCALAR, mark); + Token token(Token::SCALAR, mark); token.value = scalar; m_tokens.push(token); } @@ -409,7 +409,7 @@ namespace YAML // simple keys always ok after block scalars (since we're gonna start a new line anyways) m_simpleKeyAllowed = true; - Token token(TT_SCALAR, mark); + Token token(Token::SCALAR, mark); token.value = scalar; m_tokens.push(token); } diff --git a/src/sequence.cpp b/src/sequence.cpp index 31c88e1..ba38e2c 100644 --- a/src/sequence.cpp +++ b/src/sequence.cpp @@ -66,8 +66,8 @@ namespace YAML // split based on start token switch(pScanner->peek().type) { - case TT_BLOCK_SEQ_START: ParseBlock(pScanner, state); break; - case TT_FLOW_SEQ_START: ParseFlow(pScanner, state); break; + case Token::BLOCK_SEQ_START: ParseBlock(pScanner, state); break; + case Token::FLOW_SEQ_START: ParseFlow(pScanner, state); break; default: break; } } @@ -82,11 +82,11 @@ namespace YAML throw ParserException(Mark::null(), ErrorMsg::END_OF_SEQ); Token token = pScanner->peek(); - if(token.type != TT_BLOCK_ENTRY && token.type != TT_BLOCK_SEQ_END) + 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 == TT_BLOCK_SEQ_END) + if(token.type == Token::BLOCK_SEQ_END) break; Node *pNode = new Node; @@ -95,7 +95,7 @@ namespace YAML // check for null if(!pScanner->empty()) { const Token& token = pScanner->peek(); - if(token.type == TT_BLOCK_ENTRY || token.type == TT_BLOCK_SEQ_END) + if(token.type == Token::BLOCK_ENTRY || token.type == Token::BLOCK_SEQ_END) continue; } @@ -113,7 +113,7 @@ namespace YAML throw ParserException(Mark::null(), ErrorMsg::END_OF_SEQ_FLOW); // first check for end - if(pScanner->peek().type == TT_FLOW_SEQ_END) { + if(pScanner->peek().type == Token::FLOW_SEQ_END) { pScanner->pop(); break; } @@ -125,9 +125,9 @@ namespace YAML // 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 == TT_FLOW_ENTRY) + if(token.type == Token::FLOW_ENTRY) pScanner->pop(); - else if(token.type != TT_FLOW_SEQ_END) + else if(token.type != Token::FLOW_SEQ_END) throw ParserException(token.mark, ErrorMsg::END_OF_SEQ_FLOW); } } diff --git a/src/simplekey.cpp b/src/simplekey.cpp index 85dc7f8..bdfbda4 100644 --- a/src/simplekey.cpp +++ b/src/simplekey.cpp @@ -14,17 +14,17 @@ namespace YAML void Scanner::SimpleKey::Validate() { if(pMapStart) - pMapStart->status = TS_VALID; + pMapStart->status = Token::VALID; if(pKey) - pKey->status = TS_VALID; + pKey->status = Token::VALID; } void Scanner::SimpleKey::Invalidate() { if(pMapStart) - pMapStart->status = TS_INVALID; + pMapStart->status = Token::INVALID; if(pKey) - pKey->status = TS_INVALID; + pKey->status = Token::INVALID; } // InsertSimpleKey @@ -37,12 +37,12 @@ namespace YAML // first add a map start, if necessary key.pMapStart = PushIndentTo(INPUT.column(), IndentMarker::MAP); if(key.pMapStart) - key.pMapStart->status = TS_UNVERIFIED; + key.pMapStart->status = Token::UNVERIFIED; // then add the (now unverified) key - m_tokens.push(Token(TT_KEY, INPUT.mark())); + m_tokens.push(Token(Token::KEY, INPUT.mark())); key.pKey = &m_tokens.back(); - key.pKey->status = TS_UNVERIFIED; + key.pKey->status = Token::UNVERIFIED; m_simpleKeys.push(key); } diff --git a/src/token.h b/src/token.h index c21524d..8ab82d5 100644 --- a/src/token.h +++ b/src/token.h @@ -11,29 +11,6 @@ namespace YAML { - enum TOKEN_STATUS { TS_VALID, TS_INVALID, TS_UNVERIFIED }; - enum TOKEN_TYPE { - TT_DIRECTIVE, - TT_DOC_START, - TT_DOC_END, - TT_BLOCK_SEQ_START, - TT_BLOCK_MAP_START, - TT_BLOCK_SEQ_END, - TT_BLOCK_MAP_END, - TT_BLOCK_ENTRY, - TT_FLOW_SEQ_START, - TT_FLOW_MAP_START, - TT_FLOW_SEQ_END, - TT_FLOW_MAP_END, - TT_FLOW_ENTRY, - TT_KEY, - TT_VALUE, - TT_ANCHOR, - TT_ALIAS, - TT_TAG, - TT_SCALAR - }; - const std::string TokenNames[] = { "DIRECTIVE", "DOC_START", @@ -57,7 +34,32 @@ namespace YAML }; struct Token { - Token(TOKEN_TYPE type_, const Mark& mark_): status(TS_VALID), type(type_), mark(mark_) {} + // enums + enum STATUS { VALID, INVALID, UNVERIFIED }; + enum TYPE { + DIRECTIVE, + DOC_START, + DOC_END, + BLOCK_SEQ_START, + BLOCK_MAP_START, + BLOCK_SEQ_END, + BLOCK_MAP_END, + BLOCK_ENTRY, + FLOW_SEQ_START, + FLOW_MAP_START, + FLOW_SEQ_END, + FLOW_MAP_END, + FLOW_ENTRY, + KEY, + VALUE, + ANCHOR, + ALIAS, + TAG, + SCALAR + }; + + // data + Token(TYPE type_, const Mark& mark_): status(VALID), type(type_), mark(mark_) {} friend std::ostream& operator << (std::ostream& out, const Token& token) { out << TokenNames[token.type] << std::string(": ") << token.value; @@ -66,8 +68,8 @@ namespace YAML return out; } - TOKEN_STATUS status; - TOKEN_TYPE type; + STATUS status; + TYPE type; Mark mark; std::string value; std::vector params; From a2f2ab84262adfeb9b69db87a259a85c44346759 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sat, 5 Sep 2009 02:51:09 +0000 Subject: [PATCH 148/295] Refactored simple keys so that validating doesn't require popping indents, and so popping indents (and adding the end map) is independent of when we validate the simple key --- src/scanner.cpp | 24 +++++++++++++++--------- src/scanner.h | 7 +++++-- src/simplekey.cpp | 21 +++++++++++---------- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/src/scanner.cpp b/src/scanner.cpp index 988ed43..893bb31 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -95,12 +95,12 @@ namespace YAML // get rid of whitespace, etc. (in between tokens it should be irrelevent) ScanToNextToken(); - // check the latest simple key - VerifySimpleKey(); - // maybe need to end some blocks PopIndentToHere(); + // check the latest simple key + VerifySimpleKey(); + // ***** // And now branch based on the next few characters! // ***** @@ -244,8 +244,8 @@ namespace YAML // PushIndentTo // . Pushes an indentation onto the stack, and enqueues the // proper token (sequence start or mapping start). - // . Returns the token it generates (if any). - Token *Scanner::PushIndentTo(int column, IndentMarker::INDENT_TYPE type) + // . Returns the indent marker it generates (if any). + Scanner::IndentMarker *Scanner::PushIndentTo(int column, IndentMarker::INDENT_TYPE type) { // are we in flow? if(m_flowLevel > 0) @@ -260,16 +260,18 @@ namespace YAML if(indent.column == lastIndent.column && !(indent.type == IndentMarker::SEQ && lastIndent.type == IndentMarker::MAP)) return 0; - // now push - m_indents.push(indent); + // push a start token if(type == IndentMarker::SEQ) m_tokens.push(Token(Token::BLOCK_SEQ_START, INPUT.mark())); else if(type == IndentMarker::MAP) m_tokens.push(Token(Token::BLOCK_MAP_START, INPUT.mark())); else assert(false); + indent.pStartToken = &m_tokens.back(); - return &m_tokens.back(); + // and then the indent + m_indents.push(indent); + return &m_indents.top(); } // PopIndentToHere @@ -316,8 +318,12 @@ namespace YAML // . Pops a single indent, pushing the proper token void Scanner::PopIndent() { - IndentMarker::INDENT_TYPE type = m_indents.top().type; + IndentMarker indent = m_indents.top(); + IndentMarker::INDENT_TYPE type = indent.type; m_indents.pop(); + if(!indent.isValid) + return; + if(type == IndentMarker::SEQ) m_tokens.push(Token(Token::BLOCK_SEQ_END, INPUT.mark())); else if(type == IndentMarker::MAP) diff --git a/src/scanner.h b/src/scanner.h index 853fa64..d0e0135 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -36,10 +36,12 @@ namespace YAML private: struct IndentMarker { enum INDENT_TYPE { MAP, SEQ, NONE }; - IndentMarker(int column_, INDENT_TYPE type_): column(column_), type(type_) {} + IndentMarker(int column_, INDENT_TYPE type_): column(column_), type(type_), isValid(true), pStartToken(0) {} int column; INDENT_TYPE type; + bool isValid; + Token *pStartToken; }; private: @@ -49,7 +51,7 @@ namespace YAML void ScanToNextToken(); void StartStream(); void EndStream(); - Token *PushIndentTo(int column, IndentMarker::INDENT_TYPE type); + IndentMarker *PushIndentTo(int column, IndentMarker::INDENT_TYPE type); void PopIndentToHere(); void PopAllIndents(); void PopIndent(); @@ -71,6 +73,7 @@ namespace YAML Mark mark; int flowLevel; + IndentMarker *pIndent; Token *pMapStart, *pKey; }; diff --git a/src/simplekey.cpp b/src/simplekey.cpp index bdfbda4..cf4d1b4 100644 --- a/src/simplekey.cpp +++ b/src/simplekey.cpp @@ -7,12 +7,15 @@ namespace YAML { Scanner::SimpleKey::SimpleKey(const Mark& mark_, int flowLevel_) - : mark(mark_), flowLevel(flowLevel_), pMapStart(0), pKey(0) + : mark(mark_), flowLevel(flowLevel_), pIndent(0), pMapStart(0), pKey(0) { } void Scanner::SimpleKey::Validate() { + // Note: pIndent will *not* be garbage here; see below + if(pIndent) + pIndent->isValid = true; if(pMapStart) pMapStart->status = Token::VALID; if(pKey) @@ -21,6 +24,8 @@ namespace YAML void Scanner::SimpleKey::Invalidate() { + // Note: pIndent might be a garbage pointer here, but that's ok + // An indent will only be popped if the simple key is invalid if(pMapStart) pMapStart->status = Token::INVALID; if(pKey) @@ -35,9 +40,12 @@ namespace YAML SimpleKey key(INPUT.mark(), m_flowLevel); // first add a map start, if necessary - key.pMapStart = PushIndentTo(INPUT.column(), IndentMarker::MAP); - if(key.pMapStart) + key.pIndent = PushIndentTo(INPUT.column(), IndentMarker::MAP); + if(key.pIndent) { + key.pIndent->isValid = false; + key.pMapStart = key.pIndent->pStartToken; key.pMapStart->status = Token::UNVERIFIED; + } // then add the (now unverified) key m_tokens.push(Token(Token::KEY, INPUT.mark())); @@ -87,13 +95,6 @@ namespace YAML else key.Invalidate(); - // In block style, remember that we've pushed an indent for this potential simple key (if it was starting). - // If it was invalid, then we need to pop it off. - // Note: we're guaranteed to be popping the right one (i.e., there couldn't have been anything in - // between) since keys have to be inline, and will be invalidated immediately on a newline. - if(!isValid && m_flowLevel == 0) - m_indents.pop(); - m_isLastKeyValid = isValid; return isValid; } From ba472cc9a316ecd1c2122c13399d994347c1f568 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sat, 5 Sep 2009 03:49:38 +0000 Subject: [PATCH 149/295] Finished refactoring of simple keys so that they can refer to multiple tokens at a single level --- src/scanner.cpp | 19 ++++++++----- src/scanner.h | 9 ++++--- src/scantoken.cpp | 37 ++++++++++++-------------- src/simplekey.cpp | 53 +++++++++++++++++++++++++++---------- yaml-reader/parsertests.cpp | 48 +++++++++++++++++++++++++++++++++ yaml-reader/tests.cpp | 2 ++ yaml-reader/tests.h | 2 ++ 7 files changed, 126 insertions(+), 44 deletions(-) diff --git a/src/scanner.cpp b/src/scanner.cpp index 893bb31..1cadb71 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -46,7 +46,13 @@ namespace YAML assert(!m_tokens.empty()); // should we be asserting here? I mean, we really just be checking // if it's empty before peeking. -// std::cerr << "peek: (" << &m_tokens.front() << ") " << m_tokens.front() << "\n"; +#if 0 + static Token *pLast = 0; + if(pLast != &m_tokens.front()) + std::cerr << "peek: " << m_tokens.front() << "\n"; + pLast = &m_tokens.front(); +#endif + return m_tokens.front(); } @@ -98,9 +104,6 @@ namespace YAML // maybe need to end some blocks PopIndentToHere(); - // check the latest simple key - VerifySimpleKey(); - // ***** // And now branch based on the next few characters! // ***** @@ -187,7 +190,7 @@ namespace YAML INPUT.eat(n); // oh yeah, and let's get rid of that simple key - VerifySimpleKey(); + InvalidateSimpleKey(); // new line - we may be able to accept a simple key now if(m_flowLevel == 0) @@ -235,7 +238,7 @@ namespace YAML INPUT.ResetColumn(); PopAllIndents(); - VerifyAllSimpleKeys(); + PopAllSimpleKeys(); m_simpleKeyAllowed = false; m_endedStream = true; @@ -321,8 +324,10 @@ namespace YAML IndentMarker indent = m_indents.top(); IndentMarker::INDENT_TYPE type = indent.type; m_indents.pop(); - if(!indent.isValid) + if(!indent.isValid) { + InvalidateSimpleKey(); return; + } if(type == IndentMarker::SEQ) m_tokens.push(Token(Token::BLOCK_SEQ_END, INPUT.mark())); diff --git a/src/scanner.h b/src/scanner.h index d0e0135..05c79d4 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -58,9 +58,12 @@ namespace YAML int GetTopIndent() const; // checking input - void InsertSimpleKey(); - bool VerifySimpleKey(bool force = false); - void VerifyAllSimpleKeys(); + bool ExistsActiveSimpleKey() const; + void InsertPotentialSimpleKey(); + void InvalidateSimpleKey(); + bool VerifySimpleKey(); + void PopAllSimpleKeys(); + void ThrowParserException(const std::string& msg) const; bool IsWhitespaceToBeEaten(char ch); diff --git a/src/scantoken.cpp b/src/scantoken.cpp index fa853f7..0c3b983 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -20,7 +20,7 @@ namespace YAML // pop indents and simple keys PopAllIndents(); - VerifyAllSimpleKeys(); + PopAllSimpleKeys(); m_simpleKeyAllowed = false; @@ -60,7 +60,7 @@ namespace YAML void Scanner::ScanDocStart() { PopAllIndents(); - VerifyAllSimpleKeys(); + PopAllSimpleKeys(); m_simpleKeyAllowed = false; // eat @@ -73,7 +73,7 @@ namespace YAML void Scanner::ScanDocEnd() { PopAllIndents(); - VerifyAllSimpleKeys(); + PopAllSimpleKeys(); m_simpleKeyAllowed = false; // eat @@ -86,7 +86,7 @@ namespace YAML void Scanner::ScanFlowStart() { // flows can be simple keys - InsertSimpleKey(); + InsertPotentialSimpleKey(); m_flowLevel++; m_simpleKeyAllowed = true; @@ -103,6 +103,7 @@ namespace YAML if(m_flowLevel == 0) throw ParserException(INPUT.mark(), ErrorMsg::FLOW_END); + InvalidateSimpleKey(); m_flowLevel--; m_simpleKeyAllowed = false; @@ -170,8 +171,13 @@ namespace YAML // Value void Scanner::ScanValue() { - // does this follow a simple key? - if(m_isLastKeyValid) { + // just in case we have an empty key + InsertPotentialSimpleKey(); + + // and check that simple key + bool isSimpleKey = VerifySimpleKey(); + + if(isSimpleKey) { // can't follow a simple key with another simple key (dunno why, though - it seems fine) m_simpleKeyAllowed = false; } else { @@ -181,19 +187,10 @@ namespace YAML throw ParserException(INPUT.mark(), ErrorMsg::MAP_VALUE); PushIndentTo(INPUT.column(), IndentMarker::MAP); - } else { - // we might have an empty key, so we should add it (as a simple key) - if(m_simpleKeyAllowed) { - InsertSimpleKey(); - VerifySimpleKey(); - } } // can only put a simple key here if we're in block context - if(m_flowLevel == 0) - m_simpleKeyAllowed = true; - else - m_simpleKeyAllowed = false; + m_simpleKeyAllowed = (m_flowLevel == 0); } // eat @@ -210,7 +207,7 @@ namespace YAML // insert a potential simple key if(m_simpleKeyAllowed) - InsertSimpleKey(); + InsertPotentialSimpleKey(); m_simpleKeyAllowed = false; // eat the indicator @@ -243,7 +240,7 @@ namespace YAML // insert a potential simple key if(m_simpleKeyAllowed) - InsertSimpleKey(); + InsertPotentialSimpleKey(); m_simpleKeyAllowed = false; // eat the indicator @@ -293,7 +290,7 @@ namespace YAML // insert a potential simple key if(m_simpleKeyAllowed) - InsertSimpleKey(); + InsertPotentialSimpleKey(); Mark mark = INPUT.mark(); scalar = ScanScalar(INPUT, params); @@ -333,7 +330,7 @@ namespace YAML // insert a potential simple key if(m_simpleKeyAllowed) - InsertSimpleKey(); + InsertPotentialSimpleKey(); Mark mark = INPUT.mark(); diff --git a/src/simplekey.cpp b/src/simplekey.cpp index cf4d1b4..c8cd2bf 100644 --- a/src/simplekey.cpp +++ b/src/simplekey.cpp @@ -32,11 +32,26 @@ namespace YAML pKey->status = Token::INVALID; } - // InsertSimpleKey - // . Adds a potential simple key to the queue, - // and saves it on a stack. - void Scanner::InsertSimpleKey() + // ExistsActiveSimpleKey + // . Returns true if there's a potential simple key at our flow level + // (there's allowed at most one per flow level, i.e., at the start of the flow start token) + bool Scanner::ExistsActiveSimpleKey() const { + if(m_simpleKeys.empty()) + return false; + + const SimpleKey& key = m_simpleKeys.top(); + return key.flowLevel == m_flowLevel; + } + + // InsertPotentialSimpleKey + // . If we can, add a potential simple key to the queue, + // and save it on a stack. + void Scanner::InsertPotentialSimpleKey() + { + if(ExistsActiveSimpleKey()) + return; + SimpleKey key(INPUT.mark(), m_flowLevel); // first add a map start, if necessary @@ -55,11 +70,26 @@ namespace YAML m_simpleKeys.push(key); } + // InvalidateSimpleKey + // . Automatically invalidate the simple key in our flow level + void Scanner::InvalidateSimpleKey() + { + if(m_simpleKeys.empty()) + return; + + // grab top key + SimpleKey& key = m_simpleKeys.top(); + if(key.flowLevel != m_flowLevel) + return; + + key.Invalidate(); + m_simpleKeys.pop(); + } + // VerifySimpleKey // . Determines whether the latest simple key to be added is valid, // and if so, makes it valid. - // . If 'force' is true, then we'll pop no matter what (whether we can verify it or not). - bool Scanner::VerifySimpleKey(bool force) + bool Scanner::VerifySimpleKey() { m_isLastKeyValid = false; if(m_simpleKeys.empty()) @@ -69,11 +99,8 @@ namespace YAML SimpleKey key = m_simpleKeys.top(); // only validate if we're in the correct flow level - if(key.flowLevel != m_flowLevel) { - if(force) - m_simpleKeys.pop(); + if(key.flowLevel != m_flowLevel) return false; - } m_simpleKeys.pop(); @@ -99,11 +126,9 @@ namespace YAML return isValid; } - // VerifyAllSimplyKeys - // . Pops all simple keys (with checking, but if we can't verify one, then pop it anyways). - void Scanner::VerifyAllSimpleKeys() + void Scanner::PopAllSimpleKeys() { while(!m_simpleKeys.empty()) - VerifySimpleKey(true); + m_simpleKeys.pop(); } } diff --git a/yaml-reader/parsertests.cpp b/yaml-reader/parsertests.cpp index e3410df..aee6355 100644 --- a/yaml-reader/parsertests.cpp +++ b/yaml-reader/parsertests.cpp @@ -407,6 +407,54 @@ namespace Test return true; } + bool AnchorInSimpleKey() + { + std::string input = "- &a b: c\n- *a"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + if(doc.size() != 2) + return false; + + std::string output; + doc[0]["b"] >> output; + if(output != "c") + return false; + + doc[1] >> output; + if(output != "b") + return false; + + return true; + } + + bool AliasAsSimpleKey() + { + std::string input = "- &a b\n- *a: c"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + if(doc.size() != 2) + return false; + + std::string output; + doc[0] >> output; + if(output != "b") + return false; + + doc[1]["b"] >> output; + if(output != "c") + return false; + + return true; + } + bool ExplicitDoc() { std::string input = "---\n- one\n- two"; diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp index 8bf33ba..d727108 100644 --- a/yaml-reader/tests.cpp +++ b/yaml-reader/tests.cpp @@ -275,6 +275,8 @@ namespace Test RunParserTest(&Parser::NullBlockMapValue, "null block map value", passed); RunParserTest(&Parser::SimpleAlias, "simple alias", passed); RunParserTest(&Parser::AliasWithNull, "alias with null", passed); + RunParserTest(&Parser::AnchorInSimpleKey, "anchor in simple key", passed); + RunParserTest(&Parser::AliasAsSimpleKey, "alias as simple key", passed); RunParserTest(&Parser::ExplicitDoc, "explicit doc", passed); RunParserTest(&Parser::MultipleDocs, "multiple docs", passed); RunParserTest(&Parser::ExplicitEndDoc, "explicit end doc", passed); diff --git a/yaml-reader/tests.h b/yaml-reader/tests.h index 9aa9578..80daf18 100644 --- a/yaml-reader/tests.h +++ b/yaml-reader/tests.h @@ -42,6 +42,8 @@ namespace Test { bool NullBlockMapValue(); bool SimpleAlias(); bool AliasWithNull(); + bool AnchorInSimpleKey(); + bool AliasAsSimpleKey(); bool ExplicitDoc(); bool MultipleDocs(); bool ExplicitEndDoc(); From f21456972ca627ef12a708096286fb25daa950f3 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sat, 5 Sep 2009 22:42:01 +0000 Subject: [PATCH 150/295] Allowed solo entries in a flow map to be read as keys with null value --- src/scanner.cpp | 20 +++++++------- src/scanner.h | 11 ++++++-- src/scantoken.cpp | 55 +++++++++++++++++++++---------------- src/simplekey.cpp | 34 +++++++++++++---------- yaml-reader/parsertests.cpp | 41 ++++++++++++++++++++++++++- yaml-reader/tests.cpp | 2 ++ yaml-reader/tests.h | 2 ++ 7 files changed, 113 insertions(+), 52 deletions(-) diff --git a/src/scanner.cpp b/src/scanner.cpp index 1cadb71..ffd00a5 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -8,7 +8,7 @@ namespace YAML { Scanner::Scanner(std::istream& in) - : INPUT(in), m_startedStream(false), m_endedStream(false), m_simpleKeyAllowed(false), m_flowLevel(0) + : INPUT(in), m_startedStream(false), m_endedStream(false), m_simpleKeyAllowed(false) { } @@ -136,10 +136,10 @@ namespace YAML if(Exp::BlockEntry.Matches(INPUT)) return ScanBlockEntry(); - if((m_flowLevel == 0 ? Exp::Key : Exp::KeyInFlow).Matches(INPUT)) + if((InBlockContext() ? Exp::Key : Exp::KeyInFlow).Matches(INPUT)) return ScanKey(); - if((m_flowLevel == 0 ? Exp::Value : Exp::ValueInFlow).Matches(INPUT)) + if((InBlockContext() ? Exp::Value : Exp::ValueInFlow).Matches(INPUT)) return ScanValue(); // alias/anchor @@ -151,14 +151,14 @@ namespace YAML return ScanTag(); // special scalars - if(m_flowLevel == 0 && (INPUT.peek() == Keys::LiteralScalar || INPUT.peek() == Keys::FoldedScalar)) + if(InBlockContext() && (INPUT.peek() == Keys::LiteralScalar || INPUT.peek() == Keys::FoldedScalar)) return ScanBlockScalar(); if(INPUT.peek() == '\'' || INPUT.peek() == '\"') return ScanQuotedScalar(); // plain scalars - if((m_flowLevel == 0 ? Exp::PlainScalar : Exp::PlainScalarInFlow).Matches(INPUT)) + if((InBlockContext() ? Exp::PlainScalar : Exp::PlainScalarInFlow).Matches(INPUT)) return ScanPlainScalar(); // don't know what it is! @@ -193,7 +193,7 @@ namespace YAML InvalidateSimpleKey(); // new line - we may be able to accept a simple key now - if(m_flowLevel == 0) + if(InBlockContext()) m_simpleKeyAllowed = true; } } @@ -213,7 +213,7 @@ namespace YAML if(ch == ' ') return true; - if(ch == '\t' && (m_flowLevel >= 0 || !m_simpleKeyAllowed)) + if(ch == '\t' && (InFlowContext() || !m_simpleKeyAllowed)) return true; return false; @@ -251,7 +251,7 @@ namespace YAML Scanner::IndentMarker *Scanner::PushIndentTo(int column, IndentMarker::INDENT_TYPE type) { // are we in flow? - if(m_flowLevel > 0) + if(InFlowContext()) return 0; IndentMarker indent(column, type); @@ -283,7 +283,7 @@ namespace YAML void Scanner::PopIndentToHere() { // are we in flow? - if(m_flowLevel > 0) + if(InFlowContext()) return; // now pop away @@ -304,7 +304,7 @@ namespace YAML void Scanner::PopAllIndents() { // are we in flow? - if(m_flowLevel > 0) + if(InFlowContext()) return; // now pop away diff --git a/src/scanner.h b/src/scanner.h index 05c79d4..19ee048 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -43,6 +43,8 @@ namespace YAML bool isValid; Token *pStartToken; }; + + enum FLOW_MARKER { FLOW_MAP, FLOW_SEQ }; private: // scanning @@ -51,6 +53,11 @@ namespace YAML void ScanToNextToken(); void StartStream(); void EndStream(); + + bool InFlowContext() const { return !m_flows.empty(); } + bool InBlockContext() const { return m_flows.empty(); } + int GetFlowLevel() const { return m_flows.size(); } + IndentMarker *PushIndentTo(int column, IndentMarker::INDENT_TYPE type); void PopIndentToHere(); void PopAllIndents(); @@ -58,6 +65,7 @@ namespace YAML int GetTopIndent() const; // checking input + bool CanInsertPotentialSimpleKey() const; bool ExistsActiveSimpleKey() const; void InsertPotentialSimpleKey(); void InvalidateSimpleKey(); @@ -109,10 +117,9 @@ namespace YAML // state info bool m_startedStream, m_endedStream; bool m_simpleKeyAllowed; - int m_flowLevel; // number of unclosed '[' and '{' indicators - bool m_isLastKeyValid; std::stack m_simpleKeys; std::stack m_indents; + std::stack m_flows; std::map m_anchors; }; } diff --git a/src/scantoken.cpp b/src/scantoken.cpp index 0c3b983..e92fd6d 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -87,36 +87,50 @@ namespace YAML { // flows can be simple keys InsertPotentialSimpleKey(); - m_flowLevel++; m_simpleKeyAllowed = true; // eat Mark mark = INPUT.mark(); char ch = INPUT.get(); - Token::TYPE type = (ch == Keys::FlowSeqStart ? Token::FLOW_SEQ_START : Token::FLOW_MAP_START); + FLOW_MARKER flowType = (ch == Keys::FlowSeqStart ? FLOW_SEQ : FLOW_MAP); + m_flows.push(flowType); + Token::TYPE type = (flowType == FLOW_SEQ ? Token::FLOW_SEQ_START : Token::FLOW_MAP_START); m_tokens.push(Token(type, mark)); } // FlowEnd void Scanner::ScanFlowEnd() { - if(m_flowLevel == 0) + if(InBlockContext()) throw ParserException(INPUT.mark(), ErrorMsg::FLOW_END); - InvalidateSimpleKey(); - m_flowLevel--; + // we might have a solo entry in the flow context + if(VerifySimpleKey()) + m_tokens.push(Token(Token::VALUE, INPUT.mark())); + m_simpleKeyAllowed = false; // eat Mark mark = INPUT.mark(); char ch = INPUT.get(); - Token::TYPE type = (ch == Keys::FlowSeqEnd ? Token::FLOW_SEQ_END : Token::FLOW_MAP_END); + + // check that it matches the start + FLOW_MARKER flowType = (ch == Keys::FlowSeqEnd ? FLOW_SEQ : FLOW_MAP); + if(m_flows.top() != flowType) + throw ParserException(mark, ErrorMsg::FLOW_END); + m_flows.pop(); + + Token::TYPE type = (flowType ? Token::FLOW_SEQ_END : Token::FLOW_MAP_END); m_tokens.push(Token(type, mark)); } // FlowEntry void Scanner::ScanFlowEntry() { + // we might have a solo entry in the flow context + if(VerifySimpleKey()) + m_tokens.push(Token(Token::VALUE, INPUT.mark())); + m_simpleKeyAllowed = true; // eat @@ -129,7 +143,7 @@ namespace YAML void Scanner::ScanBlockEntry() { // we better be in the block context! - if(m_flowLevel > 0) + if(InFlowContext()) throw ParserException(INPUT.mark(), ErrorMsg::BLOCK_ENTRY); // can we put it here? @@ -149,7 +163,7 @@ namespace YAML void Scanner::ScanKey() { // handle keys diffently in the block context (and manage indents) - if(m_flowLevel == 0) { + if(InBlockContext()) { if(!m_simpleKeyAllowed) throw ParserException(INPUT.mark(), ErrorMsg::MAP_KEY); @@ -157,10 +171,7 @@ namespace YAML } // can only put a simple key here if we're in block context - if(m_flowLevel == 0) - m_simpleKeyAllowed = true; - else - m_simpleKeyAllowed = false; + m_simpleKeyAllowed = InBlockContext(); // eat Mark mark = INPUT.mark(); @@ -182,7 +193,7 @@ namespace YAML m_simpleKeyAllowed = false; } else { // handle values diffently in the block context (and manage indents) - if(m_flowLevel == 0) { + if(InBlockContext()) { if(!m_simpleKeyAllowed) throw ParserException(INPUT.mark(), ErrorMsg::MAP_VALUE); @@ -190,7 +201,7 @@ namespace YAML } // can only put a simple key here if we're in block context - m_simpleKeyAllowed = (m_flowLevel == 0); + m_simpleKeyAllowed = InBlockContext(); } // eat @@ -206,8 +217,7 @@ namespace YAML std::string name; // insert a potential simple key - if(m_simpleKeyAllowed) - InsertPotentialSimpleKey(); + InsertPotentialSimpleKey(); m_simpleKeyAllowed = false; // eat the indicator @@ -239,8 +249,7 @@ namespace YAML std::string handle, suffix; // insert a potential simple key - if(m_simpleKeyAllowed) - InsertPotentialSimpleKey(); + InsertPotentialSimpleKey(); m_simpleKeyAllowed = false; // eat the indicator @@ -278,9 +287,9 @@ namespace YAML // set up the scanning parameters ScanScalarParams params; - params.end = (m_flowLevel > 0 ? Exp::EndScalarInFlow : Exp::EndScalar) || (Exp::BlankOrBreak + Exp::Comment); + params.end = (InFlowContext() ? Exp::EndScalarInFlow : Exp::EndScalar) || (Exp::BlankOrBreak + Exp::Comment); params.eatEnd = false; - params.indent = (m_flowLevel > 0 ? 0 : GetTopIndent() + 1); + params.indent = (InFlowContext() ? 0 : GetTopIndent() + 1); params.fold = true; params.eatLeadingWhitespace = true; params.trimTrailingSpaces = true; @@ -289,8 +298,7 @@ namespace YAML params.onTabInIndentation = THROW; // insert a potential simple key - if(m_simpleKeyAllowed) - InsertPotentialSimpleKey(); + InsertPotentialSimpleKey(); Mark mark = INPUT.mark(); scalar = ScanScalar(INPUT, params); @@ -329,8 +337,7 @@ namespace YAML params.onDocIndicator = THROW; // insert a potential simple key - if(m_simpleKeyAllowed) - InsertPotentialSimpleKey(); + InsertPotentialSimpleKey(); Mark mark = INPUT.mark(); diff --git a/src/simplekey.cpp b/src/simplekey.cpp index c8cd2bf..e16dff9 100644 --- a/src/simplekey.cpp +++ b/src/simplekey.cpp @@ -31,6 +31,18 @@ namespace YAML if(pKey) pKey->status = Token::INVALID; } + + // CanInsertPotentialSimpleKey + bool Scanner::CanInsertPotentialSimpleKey() const + { + if(!m_simpleKeyAllowed) + return false; + + if(InFlowContext() && m_flows.top() != FLOW_MAP) + return false; + + return !ExistsActiveSimpleKey(); + } // ExistsActiveSimpleKey // . Returns true if there's a potential simple key at our flow level @@ -41,7 +53,7 @@ namespace YAML return false; const SimpleKey& key = m_simpleKeys.top(); - return key.flowLevel == m_flowLevel; + return key.flowLevel == GetFlowLevel(); } // InsertPotentialSimpleKey @@ -49,10 +61,10 @@ namespace YAML // and save it on a stack. void Scanner::InsertPotentialSimpleKey() { - if(ExistsActiveSimpleKey()) + if(!CanInsertPotentialSimpleKey()) return; - SimpleKey key(INPUT.mark(), m_flowLevel); + SimpleKey key(INPUT.mark(), GetFlowLevel()); // first add a map start, if necessary key.pIndent = PushIndentTo(INPUT.column(), IndentMarker::MAP); @@ -79,7 +91,7 @@ namespace YAML // grab top key SimpleKey& key = m_simpleKeys.top(); - if(key.flowLevel != m_flowLevel) + if(key.flowLevel != GetFlowLevel()) return; key.Invalidate(); @@ -91,28 +103,21 @@ namespace YAML // and if so, makes it valid. bool Scanner::VerifySimpleKey() { - m_isLastKeyValid = false; if(m_simpleKeys.empty()) - return m_isLastKeyValid; + return false; // grab top key SimpleKey key = m_simpleKeys.top(); // only validate if we're in the correct flow level - if(key.flowLevel != m_flowLevel) + if(key.flowLevel != GetFlowLevel()) return false; m_simpleKeys.pop(); bool isValid = true; - // needs to be followed immediately by a value - if(m_flowLevel > 0 && !Exp::ValueInFlow.Matches(INPUT)) - isValid = false; - if(m_flowLevel == 0 && !Exp::Value.Matches(INPUT)) - isValid = false; - - // also needs to be less than 1024 characters and inline + // needs to be less than 1024 characters and inline if(INPUT.line() != key.mark.line || INPUT.pos() - key.mark.pos > 1024) isValid = false; @@ -122,7 +127,6 @@ namespace YAML else key.Invalidate(); - m_isLastKeyValid = isValid; return isValid; } diff --git a/yaml-reader/parsertests.cpp b/yaml-reader/parsertests.cpp index aee6355..6aa524f 100644 --- a/yaml-reader/parsertests.cpp +++ b/yaml-reader/parsertests.cpp @@ -235,7 +235,7 @@ namespace Test return true; } - + bool FlowMapWithOmittedValue() { std::string input = "{a: b, c:, d:}"; @@ -256,6 +256,45 @@ namespace Test return true; } + bool FlowMapWithSoloEntry() + { + std::string input = "{a: b, c, d: e}"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc["a"] >> output; + if(output != "b") + return false; + if(!IsNull(doc["c"])) + return false; + doc["d"] >> output; + if(output != "e") + return false; + + return true; + } + + bool FlowMapEndingWithSoloEntry() + { + std::string input = "{a: b, c}"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc["a"] >> output; + if(output != "b") + return false; + if(!IsNull(doc["c"])) + return false; + + return true; + } + bool QuotedSimpleKeys() { std::string KeyValue[3] = { "\"double\": double\n", "'single': single\n", "plain: plain\n" }; diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp index d727108..9191a2c 100644 --- a/yaml-reader/tests.cpp +++ b/yaml-reader/tests.cpp @@ -268,6 +268,8 @@ namespace Test RunParserTest(&Parser::FlowMap, "flow map", passed); RunParserTest(&Parser::FlowMapWithOmittedKey, "flow map with omitted key", passed); RunParserTest(&Parser::FlowMapWithOmittedValue, "flow map with omitted value", passed); + RunParserTest(&Parser::FlowMapWithSoloEntry, "flow map with solo entry", passed); + RunParserTest(&Parser::FlowMapEndingWithSoloEntry, "flow map ending with solo entry", passed); RunParserTest(&Parser::QuotedSimpleKeys, "quoted simple keys", passed); RunParserTest(&Parser::CompressedMapAndSeq, "compressed map and seq", passed); RunParserTest(&Parser::NullBlockSeqEntry, "null block seq entry", passed); diff --git a/yaml-reader/tests.h b/yaml-reader/tests.h index 80daf18..bcdc33e 100644 --- a/yaml-reader/tests.h +++ b/yaml-reader/tests.h @@ -35,6 +35,8 @@ namespace Test { bool FlowMap(); bool FlowMapWithOmittedKey(); bool FlowMapWithOmittedValue(); + bool FlowMapWithSoloEntry(); + bool FlowMapEndingWithSoloEntry(); bool QuotedSimpleKeys(); bool CompressedMapAndSeq(); bool NullBlockSeqEntry(); From 44750974e7035f5d15950738477edcd5000bf83d Mon Sep 17 00:00:00 2001 From: jbeder Date: Sat, 5 Sep 2009 23:05:39 +0000 Subject: [PATCH 151/295] Updated the CMake file for 0.2.0 release, and added install.txt --- CMakeLists.txt | 2 +- install.txt | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 install.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ea3e2d..e038ab9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ if(CMAKE_COMPILER_IS_GNUCC) endif(CMAKE_COMPILER_IS_GNUCC) set(YAML_CPP_VERSION_MAJOR "0") -set(YAML_CPP_VERSION_MINOR "1") +set(YAML_CPP_VERSION_MINOR "2") set(YAML_CPP_VERSION_PATCH "0") set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}") diff --git a/install.txt b/install.txt new file mode 100644 index 0000000..74bba87 --- /dev/null +++ b/install.txt @@ -0,0 +1,24 @@ +*** With CMake *** + +yaml-cpp uses CMake to support cross-platform building. In a UNIX-like system, the basic steps to build are: + +1. Download and install CMake (if you don't have root privileges, just install to a local directory, like ~/bin) + +2. From the source directory, run: + +mkdir build +cd build +cmake .. + +and then the usual + +make +make install + +3. To clean up, just remove the 'build' directory. + +*** Without CMake *** + +If you don't want to use CMake, just add all .cpp files to a makefile. yaml-cpp does not need any special build settings, so no 'configure' file is necessary. + +(Note: this is pretty tedious. It's sooo much easier to use CMake.) \ No newline at end of file From 2fe7e8d5257a3661e67e7c124b9ce708dff89185 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sun, 6 Sep 2009 15:54:11 +0000 Subject: [PATCH 152/295] Added templated casting to nodes, as well as operator == and != (for quick checks, especially to help in testing). Implemented size() on a map node to return the number of key/value pairs (as in std::map) --- include/node.h | 21 ++++++++++++++++++++ include/nodeimpl.h | 42 +++++++++++++++++++++++++++++++++++++++ src/map.cpp | 5 +++++ src/map.h | 1 + yaml-reader/spectests.cpp | 34 ++++++++++--------------------- 5 files changed, 79 insertions(+), 24 deletions(-) diff --git a/include/node.h b/include/node.h index 1d39ede..808d67f 100644 --- a/include/node.h +++ b/include/node.h @@ -53,6 +53,9 @@ namespace YAML template const T Read() const; + + template + operator T() const; template friend void operator >> (const Node& node, T& value); @@ -109,6 +112,24 @@ namespace YAML const Node *m_pIdentity; mutable bool m_referenced; }; + + // comparisons with auto-conversion + template + bool operator == (const T& value, const Node& node); + + template + bool operator == (const Node& node, const T& value); + + template + bool operator != (const T& value, const Node& node); + + template + bool operator != (const Node& node, const T& value); + + bool operator == (const char *value, const Node& node); + bool operator == (const Node& node, const char *value); + bool operator != (const char *value, const Node& node); + bool operator != (const Node& node, const char *value); } #include "nodeimpl.h" diff --git a/include/nodeimpl.h b/include/nodeimpl.h index f513fd5..b5a656e 100644 --- a/include/nodeimpl.h +++ b/include/nodeimpl.h @@ -25,6 +25,11 @@ namespace YAML return value; } + template + Node::operator T() const { + return Read(); + } + template inline void operator >> (const Node& node, T& value) { if(!node.Read(value)) @@ -80,6 +85,43 @@ namespace YAML inline const Node& Node::operator [] (const char *key) const { return GetValue(std::string(key)); } + + template + inline bool operator == (const T& value, const Node& node) { + return value == node.Read(); + } + + template + inline bool operator == (const Node& node, const T& value) { + return value == node.Read(); + } + + template + inline bool operator != (const T& value, const Node& node) { + return value != node.Read(); + } + + template + inline bool operator != (const Node& node, const T& value) { + return value != node.Read(); + } + + inline bool operator == (const char *value, const Node& node) { + return std::string(value) == node; + } + + inline bool operator == (const Node& node, const char *value) { + return std::string(value) == node; + } + + inline bool operator != (const char *value, const Node& node) { + return std::string(value) != node; + } + + inline bool operator != (const Node& node, const char *value) { + return std::string(value) != node; + } + } #endif // NODEIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/map.cpp b/src/map.cpp index 8aadec9..6a57009 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -53,6 +53,11 @@ namespace YAML return true; } + std::size_t Map::GetSize() const + { + return m_data.size(); + } + void Map::Parse(Scanner *pScanner, const ParserState& state) { Clear(); diff --git a/src/map.h b/src/map.h index fc448b5..8cb67cb 100644 --- a/src/map.h +++ b/src/map.h @@ -26,6 +26,7 @@ namespace YAML virtual bool GetBegin(std::map ::const_iterator& it) const; virtual bool GetEnd(std::map ::const_iterator& it) const; + virtual std::size_t GetSize() const; virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Write(Emitter& out) const; diff --git a/yaml-reader/spectests.cpp b/yaml-reader/spectests.cpp index 3169b43..50bb4d6 100644 --- a/yaml-reader/spectests.cpp +++ b/yaml-reader/spectests.cpp @@ -5,6 +5,8 @@ #include #include +#define YAML_ASSERT(cond) do { if(!(cond)) return false; } while(false) + namespace Test { namespace { void RunSpecTest(bool (*test)(), const std::string& index, const std::string& name, bool& passed) { @@ -34,23 +36,14 @@ namespace Test { "- Sammy Sosa\n" "- Ken Griffey"; std::stringstream stream(input); - YAML::Parser parser(stream); YAML::Node doc; parser.GetNextDocument(doc); - if(doc.size() != 3) - return false; - std::string output; - doc[0] >> output; - if(output != "Mark McGwire") - return false; - doc[1] >> output; - if(output != "Sammy Sosa") - return false; - doc[2] >> output; - if(output != "Ken Griffey") - return false; + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc[0] == "Mark McGwire"); + YAML_ASSERT(doc[1] == "Sammy Sosa"); + YAML_ASSERT(doc[2] == "Ken Griffey"); return true; } @@ -60,21 +53,14 @@ namespace Test { "avg: 0.278 # Batting average\n" "rbi: 147 # Runs Batted In"; std::stringstream stream(input); - YAML::Parser parser(stream); YAML::Node doc; parser.GetNextDocument(doc); - std::string output; - doc["hr"] >> output; - if(output != "65") - return false; - doc["avg"] >> output; - if(output != "0.278") - return false; - doc["rbi"] >> output; - if(output != "147") - return false; + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["hr"] == "65"); + YAML_ASSERT(doc["avg"] == "0.278"); + YAML_ASSERT(doc["rbi"] == "147"); return true; } } From dbcf401cbd2a6de5b48a45ab6e8c9baf54f35c11 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sun, 6 Sep 2009 17:02:24 +0000 Subject: [PATCH 153/295] Added spec tests through 2.10 --- yaml-reader/spectests.cpp | 260 ++++++++++++++++++++++++++++++++++++-- yaml-reader/tests.cpp | 6 +- 2 files changed, 251 insertions(+), 15 deletions(-) diff --git a/yaml-reader/spectests.cpp b/yaml-reader/spectests.cpp index 50bb4d6..df71e6c 100644 --- a/yaml-reader/spectests.cpp +++ b/yaml-reader/spectests.cpp @@ -5,32 +5,42 @@ #include #include -#define YAML_ASSERT(cond) do { if(!(cond)) return false; } while(false) +namespace { + struct TEST { + TEST(): ok(false) {} + TEST(bool ok_): ok(ok_) {} + TEST(const char *error_): ok(false), error(error_) {} + + bool ok; + std::string error; + }; +} + +#define YAML_ASSERT(cond) do { if(!(cond)) return "Assert failed: " #cond; } while(false) namespace Test { namespace { - void RunSpecTest(bool (*test)(), const std::string& index, const std::string& name, bool& passed) { - std::string error; - bool ok = true; + void RunSpecTest(TEST (*test)(), const std::string& index, const std::string& name, bool& passed) { + TEST ret; try { - ok = test(); + ret = test(); } catch(const YAML::Exception& e) { - ok = false; - error = e.msg; + ret.ok = false; + ret.error = e.msg; } - if(ok) { + + if(ret.ok) { std::cout << "Spec test " << index << " passed: " << name << "\n"; } else { passed = false; std::cout << "Spec test " << index << " failed: " << name << "\n"; - if(error != "") - std::cout << "Caught exception: " << error << "\n"; + std::cout << ret.error << "\n"; } } } namespace Spec { - bool SeqScalars() { + TEST SeqScalars() { std::string input = "- Mark McGwire\n" "- Sammy Sosa\n" @@ -47,7 +57,7 @@ namespace Test { return true; } - bool MappingScalarsToScalars() { + TEST MappingScalarsToScalars() { std::string input = "hr: 65 # Home runs\n" "avg: 0.278 # Batting average\n" @@ -63,6 +73,224 @@ namespace Test { YAML_ASSERT(doc["rbi"] == "147"); return true; } + + TEST MappingScalarsToSequences() { + std::string input = + "american:\n" + "- Boston Red Sox\n" + "- Detroit Tigers\n" + "- New York Yankees\n" + "national:\n" + "- New York Mets\n" + "- Chicago Cubs\n" + "- Atlanta Braves"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["american"].size() == 3); + YAML_ASSERT(doc["american"][0] == "Boston Red Sox"); + YAML_ASSERT(doc["american"][1] == "Detroit Tigers"); + YAML_ASSERT(doc["american"][2] == "New York Yankees"); + YAML_ASSERT(doc["national"].size() == 3); + YAML_ASSERT(doc["national"][0] == "New York Mets"); + YAML_ASSERT(doc["national"][1] == "Chicago Cubs"); + YAML_ASSERT(doc["national"][2] == "Atlanta Braves"); + return true; + } + + TEST SequenceOfMappings() + { + std::string input = + "-\n" + " name: Mark McGwire\n" + " hr: 65\n" + " avg: 0.278\n" + "-\n" + " name: Sammy Sosa\n" + " hr: 63\n" + " avg: 0.288"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc[0].size() == 3); + YAML_ASSERT(doc[0]["name"] == "Mark McGwire"); + YAML_ASSERT(doc[0]["hr"] == "65"); + YAML_ASSERT(doc[0]["avg"] == "0.278"); + YAML_ASSERT(doc[1].size() == 3); + YAML_ASSERT(doc[1]["name"] == "Sammy Sosa"); + YAML_ASSERT(doc[1]["hr"] == "63"); + YAML_ASSERT(doc[1]["avg"] == "0.288"); + return true; + } + + TEST SequenceOfSequences() + { + std::string input = + "- [name , hr, avg ]\n" + "- [Mark McGwire, 65, 0.278]\n" + "- [Sammy Sosa , 63, 0.288]"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc[0].size() == 3); + YAML_ASSERT(doc[0][0] == "name"); + YAML_ASSERT(doc[0][1] == "hr"); + YAML_ASSERT(doc[0][2] == "avg"); + YAML_ASSERT(doc[1].size() == 3); + YAML_ASSERT(doc[1][0] == "Mark McGwire"); + YAML_ASSERT(doc[1][1] == "65"); + YAML_ASSERT(doc[1][2] == "0.278"); + YAML_ASSERT(doc[2].size() == 3); + YAML_ASSERT(doc[2][0] == "Sammy Sosa"); + YAML_ASSERT(doc[2][1] == "63"); + YAML_ASSERT(doc[2][2] == "0.288"); + return true; + } + + TEST MappingOfMappings() + { + std::string input = + "Mark McGwire: {hr: 65, avg: 0.278}\n" + "Sammy Sosa: {\n" + " hr: 63,\n" + " avg: 0.288\n" + " }"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["Mark McGwire"].size() == 2); + YAML_ASSERT(doc["Mark McGwire"]["hr"] == "65"); + YAML_ASSERT(doc["Mark McGwire"]["avg"] == "0.278"); + YAML_ASSERT(doc["Sammy Sosa"].size() == 2); + YAML_ASSERT(doc["Sammy Sosa"]["hr"] == "63"); + YAML_ASSERT(doc["Sammy Sosa"]["avg"] == "0.288"); + return true; + } + + TEST TwoDocumentsInAStream() + { + std::string input = + "# Ranking of 1998 home runs\n" + "---\n" + "- Mark McGwire\n" + "- Sammy Sosa\n" + "- Ken Griffey\n" + "\n" + "# Team ranking\n" + "---\n" + "- Chicago Cubs\n" + "- St Louis Cardinals"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc[0] == "Mark McGwire"); + YAML_ASSERT(doc[1] == "Sammy Sosa"); + YAML_ASSERT(doc[2] == "Ken Griffey"); + + parser.GetNextDocument(doc); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc[0] == "Chicago Cubs"); + YAML_ASSERT(doc[1] == "St Louis Cardinals"); + return true; + } + + TEST PlayByPlayFeed() + { + std::string input = + "---\n" + "time: 20:03:20\n" + "player: Sammy Sosa\n" + "action: strike (miss)\n" + "...\n" + "---\n" + "time: 20:03:47\n" + "player: Sammy Sosa\n" + "action: grand slam\n" + "..."; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["time"] == "20:03:20"); + YAML_ASSERT(doc["player"] == "Sammy Sosa"); + YAML_ASSERT(doc["action"] == "strike (miss)"); + + parser.GetNextDocument(doc); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["time"] == "20:03:47"); + YAML_ASSERT(doc["player"] == "Sammy Sosa"); + YAML_ASSERT(doc["action"] == "grand slam"); + return true; + } + + TEST SingleDocumentWithTwoComments() + { + std::string input = + "---\n" + "hr: # 1998 hr ranking\n" + " - Mark McGwire\n" + " - Sammy Sosa\n" + "rbi:\n" + " # 1998 rbi ranking\n" + " - Sammy Sosa\n" + " - Ken Griffey"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["hr"].size() == 2); + YAML_ASSERT(doc["hr"][0] == "Mark McGwire"); + YAML_ASSERT(doc["hr"][1] == "Sammy Sosa"); + YAML_ASSERT(doc["rbi"].size() == 2); + YAML_ASSERT(doc["rbi"][0] == "Sammy Sosa"); + YAML_ASSERT(doc["rbi"][1] == "Ken Griffey"); + return true; + } + + TEST SimpleAnchor() + { + std::string input = + "---\n" + "hr:\n" + " - Mark McGwire\n" + " # Following node labeled SS\n" + " - &SS Sammy Sosa\n" + "rbi:\n" + " - *SS # Subsequent occurrence\n" + " - Ken Griffey"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["hr"].size() == 2); + YAML_ASSERT(doc["hr"][0] == "Mark McGwire"); + YAML_ASSERT(doc["hr"][1] == "Sammy Sosa"); + YAML_ASSERT(doc["rbi"].size() == 2); + YAML_ASSERT(doc["rbi"][0] == "Sammy Sosa"); + YAML_ASSERT(doc["rbi"][1] == "Ken Griffey"); + return true; + } } bool RunSpecTests() @@ -70,6 +298,14 @@ namespace Test { bool passed = true; RunSpecTest(&Spec::SeqScalars, "2.1", "Sequence of Scalars", passed); RunSpecTest(&Spec::MappingScalarsToScalars, "2.2", "Mapping Scalars to Scalars", passed); + RunSpecTest(&Spec::MappingScalarsToSequences, "2.3", "Mapping Scalars to Sequences", passed); + RunSpecTest(&Spec::SequenceOfMappings, "2.4", "Sequence of Mappings", passed); + RunSpecTest(&Spec::SequenceOfSequences, "2.5", "Sequence of Sequences", passed); + RunSpecTest(&Spec::MappingOfMappings, "2.6", "Mapping of Mappings", passed); + RunSpecTest(&Spec::TwoDocumentsInAStream, "2.7", "Two Documents in a Stream", passed); + RunSpecTest(&Spec::PlayByPlayFeed, "2.8", "Play by Play Feed from a Game", passed); + RunSpecTest(&Spec::SingleDocumentWithTwoComments, "2.9", "Single Document with Two Comments", passed); + RunSpecTest(&Spec::SimpleAnchor, "2.10", "Node for \"Sammy Sosa\" appears twice in this document", passed); return passed; } diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp index 9191a2c..f95ba12 100644 --- a/yaml-reader/tests.cpp +++ b/yaml-reader/tests.cpp @@ -14,12 +14,12 @@ namespace Test if(!RunParserTests()) passed = false; - if(!RunSpecTests()) - passed = false; - if(!RunEmitterTests()) passed = false; + if(!RunSpecTests()) + passed = false; + if(passed) std::cout << "All tests passed!\n"; } From fe47783b5f492d1c5a8c112bd51590ff2abe7bd9 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sun, 6 Sep 2009 20:52:45 +0000 Subject: [PATCH 154/295] Refactored the operator >> and Node::Read default functions, as well as the conversion functions, to more easily read new types as keys (this uncovered an error, in example 2.11 of the spec) --- include/conversion.h | 50 +++++++++++++++--------------- include/node.h | 1 + include/nodeimpl.h | 11 +------ include/nodereadimpl.h | 65 +++++++++++++++++++++++++++++++++++++++ src/conversion.cpp | 6 ++-- yaml-reader/spectests.cpp | 45 ++++++++++++++++++++++++++- 6 files changed, 137 insertions(+), 41 deletions(-) create mode 100644 include/nodereadimpl.h diff --git a/include/conversion.h b/include/conversion.h index f449816..dfaf9f2 100644 --- a/include/conversion.h +++ b/include/conversion.h @@ -10,36 +10,34 @@ namespace YAML { - template - struct Converter { - static bool Convert(const std::string& input, T& output); - }; - - template - bool Convert(const std::string& input, T& output) { - return Converter::Convert(input, output); - } - - // this is the one to specialize - template - inline bool Converter::Convert(const std::string& input, T& output) { - std::stringstream stream(input); - stream >> output; - return !stream.fail(); - } - - // specializations - template <> - inline bool Converter::Convert(const std::string& input, std::string& output) { + inline bool Convert(const std::string& input, std::string& output) { output = input; return true; } - - template <> - bool Converter::Convert(const std::string& input, bool& output); - template <> - bool Converter<_Null>::Convert(const std::string& input, _Null& output); + bool Convert(const std::string& input, bool& output); + bool Convert(const std::string& input, _Null& output); + +#define YAML_MAKE_STREAM_CONVERT(type) \ + inline bool Convert(const std::string& input, type& output) { \ + std::stringstream stream(input); \ + stream >> output; \ + return !stream.fail(); \ + } + + YAML_MAKE_STREAM_CONVERT(char) + YAML_MAKE_STREAM_CONVERT(unsigned char) + YAML_MAKE_STREAM_CONVERT(int) + YAML_MAKE_STREAM_CONVERT(unsigned int) + YAML_MAKE_STREAM_CONVERT(short) + YAML_MAKE_STREAM_CONVERT(unsigned short) + YAML_MAKE_STREAM_CONVERT(long) + YAML_MAKE_STREAM_CONVERT(unsigned long) + YAML_MAKE_STREAM_CONVERT(float) + YAML_MAKE_STREAM_CONVERT(double) + YAML_MAKE_STREAM_CONVERT(long double) + +#undef YAML_MAKE_STREAM_CONVERT } #endif // CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/node.h b/include/node.h index 808d67f..1503e3b 100644 --- a/include/node.h +++ b/include/node.h @@ -133,5 +133,6 @@ namespace YAML } #include "nodeimpl.h" +#include "nodereadimpl.h" #endif // NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/nodeimpl.h b/include/nodeimpl.h index b5a656e..3133977 100644 --- a/include/nodeimpl.h +++ b/include/nodeimpl.h @@ -9,15 +9,6 @@ namespace YAML { // implementation of templated things - template - inline bool Node::Read(T& value) const { - std::string scalar; - if(!GetScalar(scalar)) - return false; - - return Convert(scalar, value); - } - template inline const T Node::Read() const { T value; @@ -32,7 +23,7 @@ namespace YAML template inline void operator >> (const Node& node, T& value) { - if(!node.Read(value)) + if(!ConvertScalar(node, value)) throw InvalidScalar(node.m_mark); } diff --git a/include/nodereadimpl.h b/include/nodereadimpl.h new file mode 100644 index 0000000..5beaa09 --- /dev/null +++ b/include/nodereadimpl.h @@ -0,0 +1,65 @@ +#pragma once + +namespace YAML +{ + // implementation for Node::Read + // (the goal is to call ConvertScalar if we can, and fall back to operator >> if not) + // thanks to litb from stackoverflow.com + // http://stackoverflow.com/questions/1386183/how-to-call-a-templated-function-if-it-exists-and-something-else-otherwise/1386390#1386390 + + template + struct read_impl; + + // ConvertScalar available + template<> + struct read_impl { + template + static bool read(const Node& node, T& value) { + return ConvertScalar(node, value); + } + }; + + // ConvertScalar not available + template<> + struct read_impl { + template + static bool read(const Node& node, T& value) { + try { + node >> value; + } catch(const Exception&) { + return false; + } + return true; + } + }; + + namespace fallback { + // sizeof > 1 + struct flag { char c[2]; }; + flag Convert(...); + + char (& operator,(flag, flag) )[1]; + + template + void operator,(flag, T const&); + + char (& operator,(char(&)[1], flag) )[1]; + } + + template + inline bool Node::Read(T& value) const { + using namespace fallback; + + return read_impl::read(*this, value); + } + + // the main conversion function + template + inline bool ConvertScalar(const Node& node, T& value) { + std::string scalar; + if(!node.GetScalar(scalar)) + return false; + + return Convert(scalar, value); + } +} diff --git a/src/conversion.cpp b/src/conversion.cpp index 1240e27..3b76ef2 100644 --- a/src/conversion.cpp +++ b/src/conversion.cpp @@ -49,8 +49,7 @@ namespace namespace YAML { - template <> - bool Converter::Convert(const std::string& input, bool& b) + bool Convert(const std::string& input, bool& b) { // we can't use iostream bool extraction operators as they don't // recognize all possible values in the table below (taken from @@ -82,8 +81,7 @@ namespace YAML return false; } - template <> - bool Converter<_Null>::Convert(const std::string& input, _Null& /*output*/) + bool Convert(const std::string& input, _Null& /*output*/) { return input.empty() || input == "~" || input == "null" || input == "Null" || input == "NULL"; } diff --git a/yaml-reader/spectests.cpp b/yaml-reader/spectests.cpp index df71e6c..2e0b3fd 100644 --- a/yaml-reader/spectests.cpp +++ b/yaml-reader/spectests.cpp @@ -290,7 +290,49 @@ namespace Test { YAML_ASSERT(doc["rbi"][0] == "Sammy Sosa"); YAML_ASSERT(doc["rbi"][1] == "Ken Griffey"); return true; - } + } + + struct Pair { + Pair() {} + Pair(const std::string& f, const std::string& s): first(f), second(s) {} + std::string first, second; + }; + + bool operator == (const Pair& p, const Pair& q) { + return p.first == q.first && p.second == q.second; + } + + void operator >> (const YAML::Node& node, Pair& p) { + node[0] >> p.first; + node[1] >> p.second; + } + + TEST MappingBetweenSequences() + { + std::string input = + "? - Detroit Tigers\n" + " - Chicago cubs\n" + ":\n" + " - 2001-07-23\n" + "\n" + "? [ New York Yankees,\n" + " Atlanta Braves ]\n" + ": [ 2001-07-02, 2001-08-12,\n" + " 2001-08-14 ]"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc[Pair("Detroit Tigers", "Chicago Cubs")].size() == 1); + YAML_ASSERT(doc[Pair("Detroit Tigers", "Chicago Cubs")][0] == "2001-07-23"); + YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")].size() == 3); + YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][0] == "2001-07-02"); + YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][1] == "2001-08-12"); + YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][2] == "2001-08-14"); + return true; + } } bool RunSpecTests() @@ -306,6 +348,7 @@ namespace Test { RunSpecTest(&Spec::PlayByPlayFeed, "2.8", "Play by Play Feed from a Game", passed); RunSpecTest(&Spec::SingleDocumentWithTwoComments, "2.9", "Single Document with Two Comments", passed); RunSpecTest(&Spec::SimpleAnchor, "2.10", "Node for \"Sammy Sosa\" appears twice in this document", passed); + RunSpecTest(&Spec::MappingBetweenSequences, "2.11", "Mapping between Sequences", passed); return passed; } From e67e6e19f9c573075ae98ce502d863d5b1f47ebf Mon Sep 17 00:00:00 2001 From: jbeder Date: Sun, 6 Sep 2009 21:52:56 +0000 Subject: [PATCH 155/295] Fixed bug with complex keys (and simplified the parsing for flow maps) --- src/map.cpp | 19 ++++++++----------- src/scantoken.cpp | 3 --- yaml-reader/spectests.cpp | 4 ++-- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 6a57009..6d8873e 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -122,24 +122,21 @@ namespace YAML pScanner->pop(); break; } - - // now it better be a key - if(token.type != Token::KEY) - throw ParserException(token.mark, ErrorMsg::END_OF_MAP_FLOW); - - pScanner->pop(); - + std::auto_ptr pKey(new Node), pValue(new Node); - // grab key - pKey->Parse(pScanner, state); - + // 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) diff --git a/src/scantoken.cpp b/src/scantoken.cpp index e92fd6d..0692fd5 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -182,9 +182,6 @@ namespace YAML // Value void Scanner::ScanValue() { - // just in case we have an empty key - InsertPotentialSimpleKey(); - // and check that simple key bool isSimpleKey = VerifySimpleKey(); diff --git a/yaml-reader/spectests.cpp b/yaml-reader/spectests.cpp index 2e0b3fd..60ee539 100644 --- a/yaml-reader/spectests.cpp +++ b/yaml-reader/spectests.cpp @@ -325,8 +325,8 @@ namespace Test { parser.GetNextDocument(doc); YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc[Pair("Detroit Tigers", "Chicago Cubs")].size() == 1); - YAML_ASSERT(doc[Pair("Detroit Tigers", "Chicago Cubs")][0] == "2001-07-23"); + YAML_ASSERT(doc[Pair("Detroit Tigers", "Chicago cubs")].size() == 1); + YAML_ASSERT(doc[Pair("Detroit Tigers", "Chicago cubs")][0] == "2001-07-23"); YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")].size() == 3); YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][0] == "2001-07-02"); YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][1] == "2001-08-12"); From 21c87d49616b31ff194aca0f0d2269318f17a206 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sun, 6 Sep 2009 22:02:59 +0000 Subject: [PATCH 156/295] Tagged release 0.2.1 for patch with complex keys --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e038ab9..556e9da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ endif(CMAKE_COMPILER_IS_GNUCC) set(YAML_CPP_VERSION_MAJOR "0") set(YAML_CPP_VERSION_MINOR "2") -set(YAML_CPP_VERSION_PATCH "0") +set(YAML_CPP_VERSION_PATCH "1") set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}") enable_testing() From bdf6008dea1fedfa0fdd236dfba8054435fccc53 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sun, 6 Sep 2009 22:17:53 +0000 Subject: [PATCH 157/295] Added spec tests through example 2.13 --- yaml-reader/spectests.cpp | 49 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/yaml-reader/spectests.cpp b/yaml-reader/spectests.cpp index 60ee539..e64f653 100644 --- a/yaml-reader/spectests.cpp +++ b/yaml-reader/spectests.cpp @@ -333,6 +333,53 @@ namespace Test { YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][2] == "2001-08-14"); return true; } + + TEST CompactNestedMapping() + { + std::string input = + "---\n" + "# Products purchased\n" + "- item : Super Hoop\n" + " quantity: 1\n" + "- item : Basketball\n" + " quantity: 4\n" + "- item : Big Shoes\n" + " quantity: 1"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc[0].size() == 2); + YAML_ASSERT(doc[0]["item"] == "Super Hoop"); + YAML_ASSERT(doc[0]["quantity"] == 1); + YAML_ASSERT(doc[1].size() == 2); + YAML_ASSERT(doc[1]["item"] == "Basketball"); + YAML_ASSERT(doc[1]["quantity"] == 4); + YAML_ASSERT(doc[2].size() == 2); + YAML_ASSERT(doc[2]["item"] == "Big Shoes"); + YAML_ASSERT(doc[2]["quantity"] == 1); + return true; + } + + TEST InLiteralsNewlinesArePreserved() + { + std::string input = + "# ASCII Art\n" + "--- |\n" + " \\//||\\/||\n" + " // || ||__"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc == + "\\//||\\/||\n" + "// || ||__"); + return true; + } } bool RunSpecTests() @@ -349,6 +396,8 @@ namespace Test { RunSpecTest(&Spec::SingleDocumentWithTwoComments, "2.9", "Single Document with Two Comments", passed); RunSpecTest(&Spec::SimpleAnchor, "2.10", "Node for \"Sammy Sosa\" appears twice in this document", passed); RunSpecTest(&Spec::MappingBetweenSequences, "2.11", "Mapping between Sequences", passed); + RunSpecTest(&Spec::CompactNestedMapping, "2.12", "Compact Nested Mapping", passed); + RunSpecTest(&Spec::InLiteralsNewlinesArePreserved, "2.13", "In literals, newlines are preserved", passed); return passed; } From 90be7e75c2d2704503213eacf9ef5760cbeb2ae0 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 7 Sep 2009 06:35:37 +0000 Subject: [PATCH 158/295] Added spec tests (minus tags, directives, and BOM) up through example 5.12 - this exposed an error in line folding --- yaml-reader/spectests.cpp | 433 +++++++++++++++++++++++++++++++++++++- 1 file changed, 431 insertions(+), 2 deletions(-) diff --git a/yaml-reader/spectests.cpp b/yaml-reader/spectests.cpp index e64f653..b31328e 100644 --- a/yaml-reader/spectests.cpp +++ b/yaml-reader/spectests.cpp @@ -16,7 +16,7 @@ namespace { }; } -#define YAML_ASSERT(cond) do { if(!(cond)) return "Assert failed: " #cond; } while(false) +#define YAML_ASSERT(cond) do { if(!(cond)) return " Assert failed: " #cond; } while(false) namespace Test { namespace { @@ -26,7 +26,7 @@ namespace Test { ret = test(); } catch(const YAML::Exception& e) { ret.ok = false; - ret.error = e.msg; + ret.error = " Exception caught: " + e.msg; } if(ret.ok) { @@ -40,6 +40,7 @@ namespace Test { } namespace Spec { + // 2.1 TEST SeqScalars() { std::string input = "- Mark McGwire\n" @@ -57,6 +58,7 @@ namespace Test { return true; } + // 2.2 TEST MappingScalarsToScalars() { std::string input = "hr: 65 # Home runs\n" @@ -74,6 +76,7 @@ namespace Test { return true; } + // 2.3 TEST MappingScalarsToSequences() { std::string input = "american:\n" @@ -101,6 +104,7 @@ namespace Test { return true; } + // 2.4 TEST SequenceOfMappings() { std::string input = @@ -129,6 +133,7 @@ namespace Test { return true; } + // 2.5 TEST SequenceOfSequences() { std::string input = @@ -156,6 +161,7 @@ namespace Test { return true; } + // 2.6 TEST MappingOfMappings() { std::string input = @@ -179,6 +185,7 @@ namespace Test { return true; } + // 2.7 TEST TwoDocumentsInAStream() { std::string input = @@ -209,6 +216,7 @@ namespace Test { return true; } + // 2.8 TEST PlayByPlayFeed() { std::string input = @@ -240,6 +248,7 @@ namespace Test { return true; } + // 2.9 TEST SingleDocumentWithTwoComments() { std::string input = @@ -266,6 +275,7 @@ namespace Test { return true; } + // 2.10 TEST SimpleAnchor() { std::string input = @@ -307,6 +317,7 @@ namespace Test { node[1] >> p.second; } + // 2.11 TEST MappingBetweenSequences() { std::string input = @@ -334,6 +345,7 @@ namespace Test { return true; } + // 2.12 TEST CompactNestedMapping() { std::string input = @@ -363,6 +375,7 @@ namespace Test { return true; } + // 2.13 TEST InLiteralsNewlinesArePreserved() { std::string input = @@ -380,6 +393,406 @@ namespace Test { "// || ||__"); return true; } + + // 2.14 + TEST InFoldedScalarsNewlinesBecomeSpaces() + { + std::string input = + "--- >\n" + " Mark McGwire's\n" + " year was crippled\n" + " by a knee injury."; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc == "Mark McGwire's year was crippled by a knee injury."); + return true; + } + + // 2.15 + TEST FoldedNewlinesArePreservedForMoreIndentedAndBlankLines() + { + std::string input = + ">\n" + " Sammy Sosa completed another\n" + " fine season with great stats.\n" + " \n" + " 63 Home Runs\n" + " 0.288 Batting Average\n" + " \n" + " What a year!"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc == + "Sammy Sosa completed another fine season with great stats.\n" + " 63 Home Runs\n" + " 0.288 Batting Average\n" + "What a year!"); + return true; + } + + // 2.16 + TEST IndentationDeterminesScope() + { + std::string input = + "name: Mark McGwire\n" + "accomplishment: >\n" + " Mark set a major league\n" + " home run record in 1998.\n" + "stats: |\n" + " 65 Home Runs\n" + " 0.278 Batting Average"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["name"] == "Mark McGwire"); + YAML_ASSERT(doc["accomplishment"] == "Mark set a major league home run record in 1998."); + YAML_ASSERT(doc["stats"] == "65 Home Runs\n0.278 Batting Average"); + return true; + } + + // 2.17 + TEST QuotedScalars() + { + std::string input = + "unicode: \"Sosa did fine.\\u263A\"\n" + "control: \"\\b1998\\t1999\\t2000\\n\"\n" + "hex esc: \"\\x0d\\x0a is \\r\\n\"\n" + "\n" + "single: '\"Howdy!\" he cried.'\n" + "quoted: ' # Not a ''comment''.'\n" + "tie-fighter: '|\\-*-/|'"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 6); + YAML_ASSERT(doc["unicode"] == "Sosa did fine.\u263A"); + YAML_ASSERT(doc["control"] == "\b1998\t1999\t2000\n"); + YAML_ASSERT(doc["hex esc"] == "\x0d\x0a is \r\n"); + YAML_ASSERT(doc["single"] == "\"Howdy!\" he cried."); + YAML_ASSERT(doc["quoted"] == " # Not a 'comment'."); + YAML_ASSERT(doc["tie-fighter"] == "|\\-*-/|"); + return true; + } + + // 2.18 + TEST MultiLineFlowScalars() + { + std::string input = + "plain:\n" + " This unquoted scalar\n" + " spans many lines.\n" + "\n" + "quoted: \"So does this\n" + " quoted scalar.\\n\""; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["plain"] == "This unquoted scalar spans many lines."); + YAML_ASSERT(doc["quoted"] == "So does this quoted scalar.\n"); + return true; + } + + // TODO: 2.19 - 2.26 tags + + // 2.27 + TEST Invoice() + { + std::string input = + "--- !\n" + "invoice: 34843\n" + "date : 2001-01-23\n" + "bill-to: &id001\n" + " given : Chris\n" + " family : Dumars\n" + " address:\n" + " lines: |\n" + " 458 Walkman Dr.\n" + " Suite #292\n" + " city : Royal Oak\n" + " state : MI\n" + " postal : 48046\n" + "ship-to: *id001\n" + "product:\n" + " - sku : BL394D\n" + " quantity : 4\n" + " description : Basketball\n" + " price : 450.00\n" + " - sku : BL4438H\n" + " quantity : 1\n" + " description : Super Hoop\n" + " price : 2392.00\n" + "tax : 251.42\n" + "total: 4443.52\n" + "comments:\n" + " Late afternoon is best.\n" + " Backup contact is Nancy\n" + " Billsmer @ 338-4338."; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 8); + YAML_ASSERT(doc["invoice"] == 34843); + YAML_ASSERT(doc["date"] == "2001-01-23"); + YAML_ASSERT(doc["bill-to"].size() == 3); + YAML_ASSERT(doc["bill-to"]["given"] == "Chris"); + YAML_ASSERT(doc["bill-to"]["family"] == "Dumars"); + YAML_ASSERT(doc["bill-to"]["address"].size() == 4); + YAML_ASSERT(doc["bill-to"]["address"]["lines"] == "458 Walkman Dr.\nSuite #292\n"); + YAML_ASSERT(doc["bill-to"]["address"]["city"] == "Royal Oak"); + YAML_ASSERT(doc["bill-to"]["address"]["state"] == "MI"); + YAML_ASSERT(doc["bill-to"]["address"]["postal"] == "48046"); + YAML_ASSERT(doc["ship-to"].size() == 3); + YAML_ASSERT(doc["ship-to"]["given"] == "Chris"); + YAML_ASSERT(doc["ship-to"]["family"] == "Dumars"); + YAML_ASSERT(doc["ship-to"]["address"].size() == 4); + YAML_ASSERT(doc["ship-to"]["address"]["lines"] == "458 Walkman Dr.\nSuite #292\n"); + YAML_ASSERT(doc["ship-to"]["address"]["city"] == "Royal Oak"); + YAML_ASSERT(doc["ship-to"]["address"]["state"] == "MI"); + YAML_ASSERT(doc["ship-to"]["address"]["postal"] == "48046"); + YAML_ASSERT(doc["product"].size() == 2); + YAML_ASSERT(doc["product"][0].size() == 4); + YAML_ASSERT(doc["product"][0]["sku"] == "BL394D"); + YAML_ASSERT(doc["product"][0]["quantity"] == 4); + YAML_ASSERT(doc["product"][0]["description"] == "Basketball"); + YAML_ASSERT(doc["product"][0]["price"] == "450.00"); + YAML_ASSERT(doc["product"][1].size() == 4); + YAML_ASSERT(doc["product"][1]["sku"] == "BL4438H"); + YAML_ASSERT(doc["product"][1]["quantity"] == 1); + YAML_ASSERT(doc["product"][1]["description"] == "Super Hoop"); + YAML_ASSERT(doc["product"][1]["price"] == "2392.00"); + YAML_ASSERT(doc["tax"] == "251.42"); + YAML_ASSERT(doc["total"] == "4443.52"); + YAML_ASSERT(doc["comments"] == "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338."); + return true; + } + + // 2.28 + TEST LogFile() + { + std::string input = + "---\n" + "Time: 2001-11-23 15:01:42 -5\n" + "User: ed\n" + "Warning:\n" + " This is an error message\n" + " for the log file\n" + "---\n" + "Time: 2001-11-23 15:02:31 -5\n" + "User: ed\n" + "Warning:\n" + " A slightly different error\n" + " message.\n" + "---\n" + "Date: 2001-11-23 15:03:17 -5\n" + "User: ed\n" + "Fatal:\n" + " Unknown variable \"bar\"\n" + "Stack:\n" + " - file: TopClass.py\n" + " line: 23\n" + " code: |\n" + " x = MoreObject(\"345\\n\")\n" + " - file: MoreClass.py\n" + " line: 58\n" + " code: |-\n" + " foo = bar"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["Time"] == "2001-11-23 15:01:42 -5"); + YAML_ASSERT(doc["User"] == "ed"); + YAML_ASSERT(doc["Warning"] == "This is an error message for the log file"); + + parser.GetNextDocument(doc); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["Time"] == "2001-11-23 15:02:31 -5"); + YAML_ASSERT(doc["User"] == "ed"); + YAML_ASSERT(doc["Warning"] == "A slightly different error message."); + + parser.GetNextDocument(doc); + YAML_ASSERT(doc.size() == 4); + YAML_ASSERT(doc["Date"] == "2001-11-23 15:03:17 -5"); + YAML_ASSERT(doc["User"] == "ed"); + YAML_ASSERT(doc["Fatal"] == "Unknown variable \"bar\""); + YAML_ASSERT(doc["Stack"].size() == 2); + YAML_ASSERT(doc["Stack"][0].size() == 3); + YAML_ASSERT(doc["Stack"][0]["file"] == "TopClass.py"); + YAML_ASSERT(doc["Stack"][0]["line"] == "23"); + YAML_ASSERT(doc["Stack"][0]["code"] == "x = MoreObject(\"345\\n\")\n"); + YAML_ASSERT(doc["Stack"][1].size() == 3); + YAML_ASSERT(doc["Stack"][1]["file"] == "MoreClass.py"); + YAML_ASSERT(doc["Stack"][1]["line"] == "58"); + YAML_ASSERT(doc["Stack"][1]["code"] == "foo = bar"); + return true; + } + + // TODO: 5.1 - 5.2 BOM + + // 5.3 + TEST BlockStructureIndicators() + { + std::string input = + "sequence:\n" + "- one\n" + "- two\n" + "mapping:\n" + " ? sky\n" + " : blue\n" + " sea : green"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["sequence"].size() == 2); + YAML_ASSERT(doc["sequence"][0] == "one"); + YAML_ASSERT(doc["sequence"][1] == "two"); + YAML_ASSERT(doc["mapping"].size() == 2); + YAML_ASSERT(doc["mapping"]["sky"] == "blue"); + YAML_ASSERT(doc["mapping"]["sea"] == "green"); + return true; + } + + // 5.4 + TEST FlowStructureIndicators() + { + std::string input = + "sequence: [ one, two, ]\n" + "mapping: { sky: blue, sea: green }"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["sequence"].size() == 2); + YAML_ASSERT(doc["sequence"][0] == "one"); + YAML_ASSERT(doc["sequence"][1] == "two"); + YAML_ASSERT(doc["mapping"].size() == 2); + YAML_ASSERT(doc["mapping"]["sky"] == "blue"); + YAML_ASSERT(doc["mapping"]["sea"] == "green"); + return true; + } + + // TODO: 5.5 comment only + + // 5.6 + TEST NodePropertyIndicators() + { + std::string input = + "anchored: !local &anchor value\n" + "alias: *anchor"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["anchored"] == "value"); // TODO: assert tag + YAML_ASSERT(doc["alias"] == "value"); + return true; + } + + // 5.7 + TEST BlockScalarIndicators() + { + std::string input = + "literal: |\n" + " some\n" + " text\n" + "folded: >\n" + " some\n" + " text\n"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["literal"] == "some\ntext\n"); + YAML_ASSERT(doc["folded"] == "some text\n"); + return true; + } + + // 5.8 + TEST QuotedScalarIndicators() + { + std::string input = + "single: 'text'\n" + "double: \"text\""; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["single"] == "text"); + YAML_ASSERT(doc["double"] == "text"); + return true; + } + + // TODO: 5.9 directive + // TODO: 5.10 reserved indicator + + // 5.11 + TEST LineBreakCharacters() + { + std::string input = + "|\n" + " Line break (no glyph)\n" + " Line break (glyphed)\n"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc == "Line break (no glyph)\nLine break (glyphed)\n"); + return true; + } + + // 5.12 + TEST TabsAndSpaces() + { + std::string input = + "# Tabs and spaces\n" + "quoted: \"Quoted\t\"\n" + "block: |\n" + " void main() {\n" + " \tprintf(\"Hello, world!\\n\");\n" + " }"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["quoted"] == "Quoted\t"); + YAML_ASSERT(doc["block"] == + "void main() {\n" + "\tprintf(\"Hello, world!\\n\");\n" + "}"); + return true; + } } bool RunSpecTests() @@ -398,6 +811,22 @@ namespace Test { RunSpecTest(&Spec::MappingBetweenSequences, "2.11", "Mapping between Sequences", passed); RunSpecTest(&Spec::CompactNestedMapping, "2.12", "Compact Nested Mapping", passed); RunSpecTest(&Spec::InLiteralsNewlinesArePreserved, "2.13", "In literals, newlines are preserved", passed); + RunSpecTest(&Spec::InFoldedScalarsNewlinesBecomeSpaces, "2.14", "In folded scalars, newlines become spaces", passed); + RunSpecTest(&Spec::FoldedNewlinesArePreservedForMoreIndentedAndBlankLines, "2.15", "Folded newlines are preserved for \"more indented\" and blank lines", passed); + RunSpecTest(&Spec::IndentationDeterminesScope, "2.16", "Indentation determines scope", passed); + RunSpecTest(&Spec::QuotedScalars, "2.17", "Quoted scalars", passed); + RunSpecTest(&Spec::MultiLineFlowScalars, "2.18", "Multi-line flow scalars", passed); + + RunSpecTest(&Spec::Invoice, "2.27", "Invoice", passed); + RunSpecTest(&Spec::LogFile, "2.28", "Log File", passed); + + RunSpecTest(&Spec::BlockStructureIndicators, "5.3", "Block Structure Indicators", passed); + RunSpecTest(&Spec::FlowStructureIndicators, "5.4", "Flow Structure Indicators", passed); + RunSpecTest(&Spec::NodePropertyIndicators, "5.6", "Node Property Indicators", passed); + RunSpecTest(&Spec::BlockScalarIndicators, "5.7", "Block Scalar Indicators", passed); + RunSpecTest(&Spec::QuotedScalarIndicators, "5.8", "Quoted Scalar Indicators", passed); + RunSpecTest(&Spec::LineBreakCharacters, "5.11", "Line Break Characters", passed); + RunSpecTest(&Spec::TabsAndSpaces, "5.12", "Tabs and Spaces", passed); return passed; } From 21232e3bef7cb524f3ed35636b1a1e32a84d225f Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 7 Sep 2009 06:42:03 +0000 Subject: [PATCH 159/295] Fixed bug in trailing newlines of plain scalars --- src/scanscalar.cpp | 6 +++--- src/scantoken.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/scanscalar.cpp b/src/scanscalar.cpp index 76406ef..bd8fe42 100644 --- a/src/scanscalar.cpp +++ b/src/scanscalar.cpp @@ -141,11 +141,11 @@ namespace YAML scalar.erase(pos + 1); } - if(params.chomp <= 0) { + if(params.chomp == STRIP || params.chomp == CLIP) { std::size_t pos = scalar.find_last_not_of('\n'); - if(params.chomp == 0 && pos + 1 < scalar.size()) + if(params.chomp == CLIP && pos + 1 < scalar.size()) scalar.erase(pos + 2); - else if(params.chomp == -1 && pos < scalar.size()) + else if(params.chomp == STRIP && pos < scalar.size()) scalar.erase(pos + 1); } diff --git a/src/scantoken.cpp b/src/scantoken.cpp index 0692fd5..51bb8bf 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -290,7 +290,7 @@ namespace YAML params.fold = true; params.eatLeadingWhitespace = true; params.trimTrailingSpaces = true; - params.chomp = CLIP; + params.chomp = STRIP; params.onDocIndicator = BREAK; params.onTabInIndentation = THROW; From e1a112a761212049af8f6d26fc5829cbbdc63fdc Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 7 Sep 2009 06:54:38 +0000 Subject: [PATCH 160/295] Fixed last newline of folded scalar bug --- src/scanscalar.cpp | 9 ++------- src/scantoken.cpp | 1 + yaml-reader/spectests.cpp | 6 +++--- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/scanscalar.cpp b/src/scanscalar.cpp index bd8fe42..7294ce9 100644 --- a/src/scanscalar.cpp +++ b/src/scanscalar.cpp @@ -111,13 +111,8 @@ namespace YAML bool nextMoreIndented = (INPUT.peek() == ' '); // for block scalars, we always start with a newline, so we should ignore it (not fold or keep) - bool useNewLine = pastOpeningBreak; - // and for folded scalars, we don't fold the very last newline to a space - if(params.fold && !emptyLine && INPUT.column() < params.indent) - useNewLine = false; - - if(useNewLine) { - if(params.fold && !emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented) + if(pastOpeningBreak) { + if(params.fold && !emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented && INPUT.column() >= params.indent) scalar += " "; else scalar += "\n"; diff --git a/src/scantoken.cpp b/src/scantoken.cpp index 51bb8bf..cb56225 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -368,6 +368,7 @@ namespace YAML params.fold = (indicator == Keys::FoldedScalar); // eat chomping/indentation indicators + params.chomp = CLIP; int n = Exp::Chomp.Match(INPUT); for(int i=0;i Date: Mon, 7 Sep 2009 06:56:05 +0000 Subject: [PATCH 161/295] Fixed error in test --- yaml-reader/spectests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yaml-reader/spectests.cpp b/yaml-reader/spectests.cpp index bc3a4d7..16f395c 100644 --- a/yaml-reader/spectests.cpp +++ b/yaml-reader/spectests.cpp @@ -429,9 +429,9 @@ namespace Test { parser.GetNextDocument(doc); YAML_ASSERT(doc == - "Sammy Sosa completed another fine season with great stats.\n" + "Sammy Sosa completed another fine season with great stats.\n\n" " 63 Home Runs\n" - " 0.288 Batting Average\n" + " 0.288 Batting Average\n\n" "What a year!"); return true; } From a725d4b190e8cbd1ac203d09746dc8e65bece21d Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 7 Sep 2009 16:31:23 +0000 Subject: [PATCH 162/295] Fixed bugs in escape characters (both parsing and emitting) --- src/emitterutils.cpp | 2 +- src/exp.cpp | 7 ++++--- yaml-reader/spectests.cpp | 41 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index 694b961..cddf5eb 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -83,7 +83,7 @@ namespace YAML } else { // TODO: for the common escaped characters, give their usual symbol std::stringstream str; - str << "\\x" << std::hex << std::setfill('0') << std::setw(2) << static_cast (ch); + str << "\\x" << std::hex << std::setfill('0') << std::setw(2) << static_cast(static_cast(ch)); out << str.str(); } } diff --git a/src/exp.cpp b/src/exp.cpp index bbb294f..b5cb815 100644 --- a/src/exp.cpp +++ b/src/exp.cpp @@ -83,7 +83,7 @@ namespace YAML // now do the slash (we're not gonna check if it's a slash - you better pass one!) switch(ch) { - case '0': return "\0"; + case '0': return std::string("\x00", 1); case 'a': return "\x07"; case 'b': return "\x08"; case 't': @@ -97,8 +97,9 @@ namespace YAML case '\"': return "\""; case '\'': return "\'"; case '\\': return "\\"; - case 'N': return "\xC2\x85"; // NEL (#x85) - case '_': return "\xC2\xA0"; // #xA0 + case '/': return "/"; + case 'N': return "\x85"; + case '_': return "\xA0"; case 'L': return "\xE2\x80\xA8"; // LS (#x2028) case 'P': return "\xE2\x80\xA9"; // PS (#x2029) case 'x': return Escape(in, 2); diff --git a/yaml-reader/spectests.cpp b/yaml-reader/spectests.cpp index 16f395c..af82b57 100644 --- a/yaml-reader/spectests.cpp +++ b/yaml-reader/spectests.cpp @@ -793,6 +793,45 @@ namespace Test { "}"); return true; } + + // 5.13 + TEST EscapedCharacters() + { + std::string input = + "\"Fun with \\\\\n" + "\\\" \\a \\b \\e \\f \\\n" + "\\n \\r \\t \\v \\0 \\\n" + "\\ \\_ \\N \\L \\P \\\n" + "\\x41 \\u0041 \\U00000041\""; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc == "Fun with \x5C \x22 \x07 \x08 \x1B \x0C \x0A \x0D \x09 \x0B " + std::string("\x00", 1) + " \x20 \xA0 \x85 \u2028 \u2029 A A A"); + return true; + } + + // 5.14 + TEST InvalidEscapedCharacters() + { + std::string input = + "Bad escapes:\n" + " \"\\c\n" + " \\xq-\""; + + std::stringstream stream(input); + try { + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + } catch(const YAML::ParserException& e) { + YAML_ASSERT(e.msg == YAML::ErrorMsg::INVALID_ESCAPE + "c"); + return true; + } + + return false; + } } bool RunSpecTests() @@ -827,6 +866,8 @@ namespace Test { RunSpecTest(&Spec::QuotedScalarIndicators, "5.8", "Quoted Scalar Indicators", passed); RunSpecTest(&Spec::LineBreakCharacters, "5.11", "Line Break Characters", passed); RunSpecTest(&Spec::TabsAndSpaces, "5.12", "Tabs and Spaces", passed); + RunSpecTest(&Spec::EscapedCharacters, "5.13", "Escaped Characters", passed); + RunSpecTest(&Spec::InvalidEscapedCharacters, "5.14", "Invalid Escaped Characters", passed); return passed; } From d15ce26b584e55c52bfeac34b7e29392feecab4c Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 7 Sep 2009 17:12:45 +0000 Subject: [PATCH 163/295] Fixed bugs with tab as non-content whitespace --- src/scanner.cpp | 20 +++--- yaml-reader/spectests.cpp | 125 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+), 8 deletions(-) diff --git a/src/scanner.cpp b/src/scanner.cpp index ffd00a5..552a0cf 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -171,8 +171,11 @@ namespace YAML { while(1) { // first eat whitespace - while(INPUT && IsWhitespaceToBeEaten(INPUT.peek())) + while(INPUT && IsWhitespaceToBeEaten(INPUT.peek())) { + if(InBlockContext() && Exp::Tab.Matches(INPUT)) + m_simpleKeyAllowed = false; INPUT.eat(1); + } // then eat a comment if(Exp::Comment.Matches(INPUT)) { @@ -202,18 +205,19 @@ namespace YAML // Misc. helpers // IsWhitespaceToBeEaten - // . We can eat whitespace if: - // 1. It's a space - // 2. It's a tab, and we're either: - // a. In the flow context - // b. In the block context but not where a simple key could be allowed - // (i.e., not at the beginning of a line, or following '-', '?', or ':') + // . We can eat whitespace if it's a space or tab + // . Note: originally tabs in block context couldn't be eaten + // "where a simple key could be allowed + // (i.e., not at the beginning of a line, or following '-', '?', or ':')" + // I think this is wrong, since tabs can be non-content whitespace; it's just + // that they can't contribute to indentation, so once you've seen a tab in a + // line, you can't start a simple key bool Scanner::IsWhitespaceToBeEaten(char ch) { if(ch == ' ') return true; - if(ch == '\t' && (InFlowContext() || !m_simpleKeyAllowed)) + if(ch == '\t') return true; return false; diff --git a/yaml-reader/spectests.cpp b/yaml-reader/spectests.cpp index af82b57..dd5ae85 100644 --- a/yaml-reader/spectests.cpp +++ b/yaml-reader/spectests.cpp @@ -832,6 +832,125 @@ namespace Test { return false; } + + // 6.1 + TEST IndentationSpaces() + { + std::string input = + " # Leading comment line spaces are\n" + " # neither content nor indentation.\n" + " \n" + "Not indented:\n" + " By one space: |\n" + " By four\n" + " spaces\n" + " Flow style: [ # Leading spaces\n" + " By two, # in flow style\n" + " Also by two, # are neither\n" + " \tStill by two # content nor\n" + " ] # indentation."; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc["Not indented"].size() == 2); + YAML_ASSERT(doc["Not indented"]["By one space"] == "By four\n spaces\n"); + YAML_ASSERT(doc["Not indented"]["Flow style"].size() == 3); + YAML_ASSERT(doc["Not indented"]["Flow style"][0] == "By two"); + YAML_ASSERT(doc["Not indented"]["Flow style"][1] == "Also by two"); + YAML_ASSERT(doc["Not indented"]["Flow style"][2] == "Still by two"); + return true; + } + + // 6.2 + TEST IndentationIndicators() + { + std::string input = + "? a\n" + ": -\tb\n" + " - -\tc\n" + " - d"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc["a"].size() == 2); + YAML_ASSERT(doc["a"][0] == "b"); + YAML_ASSERT(doc["a"][1].size() == 2); + YAML_ASSERT(doc["a"][1][0] == "c"); + YAML_ASSERT(doc["a"][1][1] == "d"); + return true; + } + + // 6.3 + TEST SeparationSpaces() + { + std::string input = + "- foo:\t bar\n" + "- - baz\n" + " -\tbaz"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc[0].size() == 1); + YAML_ASSERT(doc[0]["foo"] == "bar"); + YAML_ASSERT(doc[1].size() == 2); + YAML_ASSERT(doc[1][0] == "baz"); + YAML_ASSERT(doc[1][1] == "baz"); + return true; + } + + // 6.4 + TEST LinePrefixes() + { + std::string input = + "plain: text\n" + " lines\n" + "quoted: \"text\n" + " \tlines\"\n" + "block: |\n" + " text\n" + " \tlines\n"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["plain"] == "text lines"); + YAML_ASSERT(doc["quoted"] == "text lines"); + YAML_ASSERT(doc["block"] == "text\n \tlines\n"); + return true; + } + + // 6.5 + TEST EmptyLines() + { + std::string input = + "Folding:\n" + " \"Empty line\n" + " \t\n" + " as a line feed\"\n" + "Chomping: |\n" + " Clipped empty lines\n" + " "; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["Folding"] == "Empty line\nas a line feed"); + YAML_ASSERT(doc["Chomping"] == "Clipped empty lines\n"); + return true; + } } bool RunSpecTests() @@ -868,6 +987,12 @@ namespace Test { RunSpecTest(&Spec::TabsAndSpaces, "5.12", "Tabs and Spaces", passed); RunSpecTest(&Spec::EscapedCharacters, "5.13", "Escaped Characters", passed); RunSpecTest(&Spec::InvalidEscapedCharacters, "5.14", "Invalid Escaped Characters", passed); + + RunSpecTest(&Spec::IndentationSpaces, "6.1", "Indentation Spaces", passed); + RunSpecTest(&Spec::IndentationIndicators, "6.2", "Indentation Indicators", passed); + RunSpecTest(&Spec::SeparationSpaces, "6.3", "Separation Spaces", passed); + RunSpecTest(&Spec::LinePrefixes, "6.4", "Line Prefixes", passed); + RunSpecTest(&Spec::EmptyLines, "6.5", "Empty Lines", passed); return passed; } From 994e6af8e00953bb0646a8aaef0e2e3a6bf630e9 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 7 Sep 2009 22:17:02 +0000 Subject: [PATCH 164/295] Simplified testing output --- yaml-reader/emittertests.cpp | 90 +++++++++ yaml-reader/emittertests.h | 11 ++ yaml-reader/parsertests.cpp | 274 ++++++++++++++++++++++++++ yaml-reader/parsertests.h | 11 ++ yaml-reader/spectests.cpp | 86 ++++---- yaml-reader/tests.cpp | 366 +---------------------------------- yaml-reader/tests.h | 52 ----- 7 files changed, 434 insertions(+), 456 deletions(-) create mode 100644 yaml-reader/emittertests.h create mode 100644 yaml-reader/parsertests.h diff --git a/yaml-reader/emittertests.cpp b/yaml-reader/emittertests.cpp index 95c0ac4..9af202f 100644 --- a/yaml-reader/emittertests.cpp +++ b/yaml-reader/emittertests.cpp @@ -534,4 +534,94 @@ namespace Test out << YAML::EndSeq; } } + + namespace { + void RunEmitterTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, int& passed, int& total) { + YAML::Emitter out; + std::string desiredOutput; + test(out, desiredOutput); + std::string output = out.c_str(); + + if(output == desiredOutput) { + passed++; + } else { + std::cout << "Emitter test failed: " << name << "\n"; + std::cout << "Output:\n"; + std::cout << output << "<<<\n"; + std::cout << "Desired output:\n"; + std::cout << desiredOutput << "<<<\n"; + } + total++; + } + + void RunEmitterErrorTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, int& passed, int& total) { + YAML::Emitter out; + std::string desiredError; + test(out, desiredError); + std::string lastError = out.GetLastError(); + if(!out.good() && lastError == desiredError) { + passed++; + } else { + std::cout << "Emitter test failed: " << name << "\n"; + if(out.good()) + std::cout << "No error detected\n"; + else + std::cout << "Detected error: " << lastError << "\n"; + std::cout << "Expected error: " << desiredError << "\n"; + } + total++; + } + } + + bool RunEmitterTests() + { + int passed = 0; + int total = 0; + RunEmitterTest(&Emitter::SimpleScalar, "simple scalar", passed, total); + RunEmitterTest(&Emitter::SimpleSeq, "simple seq", passed, total); + RunEmitterTest(&Emitter::SimpleFlowSeq, "simple flow seq", passed, total); + RunEmitterTest(&Emitter::EmptyFlowSeq, "empty flow seq", passed, total); + RunEmitterTest(&Emitter::NestedBlockSeq, "nested block seq", passed, total); + RunEmitterTest(&Emitter::NestedFlowSeq, "nested flow seq", passed, total); + RunEmitterTest(&Emitter::SimpleMap, "simple map", passed, total); + RunEmitterTest(&Emitter::SimpleFlowMap, "simple flow map", passed, total); + RunEmitterTest(&Emitter::MapAndList, "map and list", passed, total); + RunEmitterTest(&Emitter::ListAndMap, "list and map", passed, total); + RunEmitterTest(&Emitter::NestedBlockMap, "nested block map", passed, total); + RunEmitterTest(&Emitter::NestedFlowMap, "nested flow map", passed, total); + RunEmitterTest(&Emitter::MapListMix, "map list mix", passed, total); + RunEmitterTest(&Emitter::SimpleLongKey, "simple long key", passed, total); + RunEmitterTest(&Emitter::SingleLongKey, "single long key", passed, total); + RunEmitterTest(&Emitter::ComplexLongKey, "complex long key", passed, total); + RunEmitterTest(&Emitter::AutoLongKey, "auto long key", passed, total); + RunEmitterTest(&Emitter::ScalarFormat, "scalar format", passed, total); + RunEmitterTest(&Emitter::AutoLongKeyScalar, "auto long key scalar", passed, total); + RunEmitterTest(&Emitter::LongKeyFlowMap, "long key flow map", passed, total); + RunEmitterTest(&Emitter::BlockMapAsKey, "block map as key", passed, total); + RunEmitterTest(&Emitter::AliasAndAnchor, "alias and anchor", passed, total); + RunEmitterTest(&Emitter::AliasAndAnchorWithNull, "alias and anchor with null", passed, total); + RunEmitterTest(&Emitter::ComplexDoc, "complex doc", passed, total); + RunEmitterTest(&Emitter::STLContainers, "STL containers", passed, total); + RunEmitterTest(&Emitter::SimpleComment, "simple comment", passed, total); + RunEmitterTest(&Emitter::MultiLineComment, "multi-line comment", passed, total); + RunEmitterTest(&Emitter::ComplexComments, "complex comments", passed, total); + RunEmitterTest(&Emitter::Indentation, "indentation", passed, total); + RunEmitterTest(&Emitter::SimpleGlobalSettings, "simple global settings", passed, total); + RunEmitterTest(&Emitter::ComplexGlobalSettings, "complex global settings", passed, total); + RunEmitterTest(&Emitter::Null, "null", passed, total); + + RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total); + RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total); + RunEmitterErrorTest(&Emitter::BadSingleQuoted, "bad single quoted string", passed, total); + RunEmitterErrorTest(&Emitter::InvalidAnchor, "invalid anchor", passed, total); + RunEmitterErrorTest(&Emitter::InvalidAlias, "invalid alias", passed, total); + RunEmitterErrorTest(&Emitter::MissingKey, "missing key", passed, total); + RunEmitterErrorTest(&Emitter::MissingValue, "missing value", passed, total); + RunEmitterErrorTest(&Emitter::UnexpectedKey, "unexpected key", passed, total); + RunEmitterErrorTest(&Emitter::UnexpectedValue, "unexpected value", passed, total); + + std::cout << "Emitter tests: " << passed << "/" << total << " passed\n"; + return passed == total; + } } + diff --git a/yaml-reader/emittertests.h b/yaml-reader/emittertests.h new file mode 100644 index 0000000..e746e5a --- /dev/null +++ b/yaml-reader/emittertests.h @@ -0,0 +1,11 @@ +#pragma once + +#ifndef EMITTERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define EMITTERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +namespace Test { + bool RunEmitterTests(); +} + +#endif // EMITTERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + diff --git a/yaml-reader/parsertests.cpp b/yaml-reader/parsertests.cpp index 6aa524f..138143c 100644 --- a/yaml-reader/parsertests.cpp +++ b/yaml-reader/parsertests.cpp @@ -611,4 +611,278 @@ namespace Test return true; } } + + namespace { + void RunScalarParserTest(void (*test)(std::string&, std::string&), const std::string& name, int& passed, int& total) { + std::string error; + std::string inputScalar, desiredOutput; + std::string output; + bool ok = true; + try { + test(inputScalar, desiredOutput); + std::stringstream stream(inputScalar); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + doc >> output; + } catch(const YAML::Exception& e) { + ok = false; + error = e.msg; + } + if(ok && output == desiredOutput) { + passed++; + } else { + std::cout << "Parser test failed: " << name << "\n"; + if(error != "") + std::cout << "Caught exception: " << error << "\n"; + else { + std::cout << "Output:\n" << output << "<<<\n"; + std::cout << "Desired output:\n" << desiredOutput << "<<<\n"; + } + } + total++; + } + + void RunParserTest(bool (*test)(), const std::string& name, int& passed, int& total) { + std::string error; + bool ok = true; + try { + ok = test(); + } catch(const YAML::Exception& e) { + ok = false; + error = e.msg; + } + if(ok) { + passed++; + } else { + std::cout << "Parser test failed: " << name << "\n"; + if(error != "") + std::cout << "Caught exception: " << error << "\n"; + } + total++; + } + + typedef void (*EncodingFn)(std::ostream&, int); + + inline char Byte(int ch) + { + return static_cast(static_cast(static_cast(ch))); + } + + void EncodeToUtf8(std::ostream& stream, int ch) + { + if (ch <= 0x7F) + { + stream << Byte(ch); + } + else if (ch <= 0x7FF) + { + stream << Byte(0xC0 | (ch >> 6)); + stream << Byte(0x80 | (ch & 0x3F)); + } + else if (ch <= 0xFFFF) + { + stream << Byte(0xE0 | (ch >> 12)); + stream << Byte(0x80 | ((ch >> 6) & 0x3F)); + stream << Byte(0x80 | (ch & 0x3F)); + } + else if (ch <= 0x1FFFFF) + { + stream << Byte(0xF0 | (ch >> 18)); + stream << Byte(0x80 | ((ch >> 12) & 0x3F)); + stream << Byte(0x80 | ((ch >> 6) & 0x3F)); + stream << Byte(0x80 | (ch & 0x3F)); + } + } + + bool SplitUtf16HighChar(std::ostream& stream, EncodingFn encoding, int ch) + { + int biasedValue = ch - 0x10000; + if (biasedValue < 0) + { + return false; + } + int high = 0xD800 | (biasedValue >> 10); + int low = 0xDC00 | (biasedValue & 0x3FF); + encoding(stream, high); + encoding(stream, low); + return true; + } + + void EncodeToUtf16LE(std::ostream& stream, int ch) + { + if (!SplitUtf16HighChar(stream, &EncodeToUtf16LE, ch)) + { + stream << Byte(ch & 0xFF) << Byte(ch >> 8); + } + } + + void EncodeToUtf16BE(std::ostream& stream, int ch) + { + if (!SplitUtf16HighChar(stream, &EncodeToUtf16BE, ch)) + { + stream << Byte(ch >> 8) << Byte(ch & 0xFF); + } + } + + void EncodeToUtf32LE(std::ostream& stream, int ch) + { + stream << Byte(ch & 0xFF) << Byte((ch >> 8) & 0xFF) + << Byte((ch >> 16) & 0xFF) << Byte((ch >> 24) & 0xFF); + } + + void EncodeToUtf32BE(std::ostream& stream, int ch) + { + stream << Byte((ch >> 24) & 0xFF) << Byte((ch >> 16) & 0xFF) + << Byte((ch >> 8) & 0xFF) << Byte(ch & 0xFF); + } + + class EncodingTester + { + public: + EncodingTester(EncodingFn encoding, bool declareEncoding) + { + if (declareEncoding) + { + encoding(m_yaml, 0xFEFF); + } + + AddEntry(encoding, 0x0021, 0x007E); // Basic Latin + AddEntry(encoding, 0x00A1, 0x00FF); // Latin-1 Supplement + AddEntry(encoding, 0x0660, 0x06FF); // Arabic (largest contiguous block) + + // CJK unified ideographs (multiple lines) + AddEntry(encoding, 0x4E00, 0x4EFF); + AddEntry(encoding, 0x4F00, 0x4FFF); + AddEntry(encoding, 0x5000, 0x51FF); // 512 character line + AddEntry(encoding, 0x5200, 0x54FF); // 768 character line + AddEntry(encoding, 0x5500, 0x58FF); // 1024 character line + + AddEntry(encoding, 0x103A0, 0x103C3); // Old Persian + + m_yaml.seekg(0, std::ios::beg); + } + + std::istream& stream() {return m_yaml;} + const std::vector& entries() {return m_entries;} + + private: + std::stringstream m_yaml; + std::vector m_entries; + + void AddEntry(EncodingFn encoding, int startCh, int endCh) + { + encoding(m_yaml, '-'); + encoding(m_yaml, ' '); + encoding(m_yaml, '|'); + encoding(m_yaml, '\n'); + encoding(m_yaml, ' '); + encoding(m_yaml, ' '); + + std::stringstream entry; + for (int ch = startCh; ch <= endCh; ++ch) + { + encoding(m_yaml, ch); + EncodeToUtf8(entry, ch); + } + encoding(m_yaml, '\n'); + + m_entries.push_back(entry.str()); + } + }; + + void RunEncodingTest(EncodingFn encoding, bool declareEncoding, const std::string& name, int& passed, int& total) + { + EncodingTester tester(encoding, declareEncoding); + std::string error; + bool ok = true; + try { + YAML::Parser parser(tester.stream()); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML::Iterator itNode = doc.begin(); + std::vector::const_iterator itEntry = tester.entries().begin(); + for (; (itNode != doc.end()) && (itEntry != tester.entries().end()); ++itNode, ++itEntry) + { + std::string stScalarValue; + if (!itNode->GetScalar(stScalarValue) && (stScalarValue == *itEntry)) + { + break; + } + } + + if ((itNode != doc.end()) || (itEntry != tester.entries().end())) + { + ok = false; + } + } catch(const YAML::Exception& e) { + ok = false; + error = e.msg; + } + if(ok) { + passed++; + } else { + std::cout << "Parser test failed: " << name << "\n"; + if(error != "") + std::cout << "Caught exception: " << error << "\n"; + } + total++; + } + } + + bool RunParserTests() + { + int passed = 0; + int total = 0; + RunScalarParserTest(&Parser::SimpleScalar, "simple scalar", passed, total); + RunScalarParserTest(&Parser::MultiLineScalar, "multi-line scalar", passed, total); + RunScalarParserTest(&Parser::LiteralScalar, "literal scalar", passed, total); + RunScalarParserTest(&Parser::FoldedScalar, "folded scalar", passed, total); + RunScalarParserTest(&Parser::ChompedFoldedScalar, "chomped folded scalar", passed, total); + RunScalarParserTest(&Parser::ChompedLiteralScalar, "chomped literal scalar", passed, total); + RunScalarParserTest(&Parser::FoldedScalarWithIndent, "folded scalar with indent", passed, total); + RunScalarParserTest(&Parser::ColonScalar, "colon scalar", passed, total); + RunScalarParserTest(&Parser::QuotedScalar, "quoted scalar", passed, total); + RunScalarParserTest(&Parser::CommaScalar, "comma scalar", passed, total); + RunScalarParserTest(&Parser::DashScalar, "dash scalar", passed, total); + RunScalarParserTest(&Parser::URLScalar, "url scalar", passed, total); + + RunParserTest(&Parser::SimpleSeq, "simple seq", passed, total); + RunParserTest(&Parser::SimpleMap, "simple map", passed, total); + RunParserTest(&Parser::FlowSeq, "flow seq", passed, total); + RunParserTest(&Parser::FlowMap, "flow map", passed, total); + RunParserTest(&Parser::FlowMapWithOmittedKey, "flow map with omitted key", passed, total); + RunParserTest(&Parser::FlowMapWithOmittedValue, "flow map with omitted value", passed, total); + RunParserTest(&Parser::FlowMapWithSoloEntry, "flow map with solo entry", passed, total); + RunParserTest(&Parser::FlowMapEndingWithSoloEntry, "flow map ending with solo entry", passed, total); + RunParserTest(&Parser::QuotedSimpleKeys, "quoted simple keys", passed, total); + RunParserTest(&Parser::CompressedMapAndSeq, "compressed map and seq", passed, total); + RunParserTest(&Parser::NullBlockSeqEntry, "null block seq entry", passed, total); + RunParserTest(&Parser::NullBlockMapKey, "null block map key", passed, total); + RunParserTest(&Parser::NullBlockMapValue, "null block map value", passed, total); + RunParserTest(&Parser::SimpleAlias, "simple alias", passed, total); + RunParserTest(&Parser::AliasWithNull, "alias with null", passed, total); + RunParserTest(&Parser::AnchorInSimpleKey, "anchor in simple key", passed, total); + RunParserTest(&Parser::AliasAsSimpleKey, "alias as simple key", passed, total); + RunParserTest(&Parser::ExplicitDoc, "explicit doc", passed, total); + RunParserTest(&Parser::MultipleDocs, "multiple docs", passed, total); + RunParserTest(&Parser::ExplicitEndDoc, "explicit end doc", passed, total); + RunParserTest(&Parser::MultipleDocsWithSomeExplicitIndicators, "multiple docs with some explicit indicators", passed, total); + + RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed, total); + RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed, total); + RunEncodingTest(&EncodeToUtf16LE, false, "UTF-16LE, no BOM", passed, total); + RunEncodingTest(&EncodeToUtf16LE, true, "UTF-16LE with BOM", passed, total); + RunEncodingTest(&EncodeToUtf16BE, false, "UTF-16BE, no BOM", passed, total); + RunEncodingTest(&EncodeToUtf16BE, true, "UTF-16BE with BOM", passed, total); + RunEncodingTest(&EncodeToUtf32LE, false, "UTF-32LE, no BOM", passed, total); + RunEncodingTest(&EncodeToUtf32LE, true, "UTF-32LE with BOM", passed, total); + RunEncodingTest(&EncodeToUtf32BE, false, "UTF-32BE, no BOM", passed, total); + RunEncodingTest(&EncodeToUtf32BE, true, "UTF-32BE with BOM", passed, total); + + std::cout << "Parser tests: " << passed << "/" << total << " passed\n"; + return passed == total; + } } + diff --git a/yaml-reader/parsertests.h b/yaml-reader/parsertests.h new file mode 100644 index 0000000..e63a2eb --- /dev/null +++ b/yaml-reader/parsertests.h @@ -0,0 +1,11 @@ +#pragma once + +#ifndef PARSERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define PARSERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +namespace Test { + bool RunParserTests(); +} + +#endif // PARSERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + diff --git a/yaml-reader/spectests.cpp b/yaml-reader/spectests.cpp index dd5ae85..1093a71 100644 --- a/yaml-reader/spectests.cpp +++ b/yaml-reader/spectests.cpp @@ -20,7 +20,7 @@ namespace { namespace Test { namespace { - void RunSpecTest(TEST (*test)(), const std::string& index, const std::string& name, bool& passed) { + void RunSpecTest(TEST (*test)(), const std::string& index, const std::string& name, int& passed, int& total) { TEST ret; try { ret = test(); @@ -29,13 +29,14 @@ namespace Test { ret.error = " Exception caught: " + e.msg; } - if(ret.ok) { - std::cout << "Spec test " << index << " passed: " << name << "\n"; - } else { - passed = false; + if(!ret.ok) { std::cout << "Spec test " << index << " failed: " << name << "\n"; std::cout << ret.error << "\n"; } + + if(ret.ok) + passed++; + total++; } } @@ -955,45 +956,48 @@ namespace Test { bool RunSpecTests() { - bool passed = true; - RunSpecTest(&Spec::SeqScalars, "2.1", "Sequence of Scalars", passed); - RunSpecTest(&Spec::MappingScalarsToScalars, "2.2", "Mapping Scalars to Scalars", passed); - RunSpecTest(&Spec::MappingScalarsToSequences, "2.3", "Mapping Scalars to Sequences", passed); - RunSpecTest(&Spec::SequenceOfMappings, "2.4", "Sequence of Mappings", passed); - RunSpecTest(&Spec::SequenceOfSequences, "2.5", "Sequence of Sequences", passed); - RunSpecTest(&Spec::MappingOfMappings, "2.6", "Mapping of Mappings", passed); - RunSpecTest(&Spec::TwoDocumentsInAStream, "2.7", "Two Documents in a Stream", passed); - RunSpecTest(&Spec::PlayByPlayFeed, "2.8", "Play by Play Feed from a Game", passed); - RunSpecTest(&Spec::SingleDocumentWithTwoComments, "2.9", "Single Document with Two Comments", passed); - RunSpecTest(&Spec::SimpleAnchor, "2.10", "Node for \"Sammy Sosa\" appears twice in this document", passed); - RunSpecTest(&Spec::MappingBetweenSequences, "2.11", "Mapping between Sequences", passed); - RunSpecTest(&Spec::CompactNestedMapping, "2.12", "Compact Nested Mapping", passed); - RunSpecTest(&Spec::InLiteralsNewlinesArePreserved, "2.13", "In literals, newlines are preserved", passed); - RunSpecTest(&Spec::InFoldedScalarsNewlinesBecomeSpaces, "2.14", "In folded scalars, newlines become spaces", passed); - RunSpecTest(&Spec::FoldedNewlinesArePreservedForMoreIndentedAndBlankLines, "2.15", "Folded newlines are preserved for \"more indented\" and blank lines", passed); - RunSpecTest(&Spec::IndentationDeterminesScope, "2.16", "Indentation determines scope", passed); - RunSpecTest(&Spec::QuotedScalars, "2.17", "Quoted scalars", passed); - RunSpecTest(&Spec::MultiLineFlowScalars, "2.18", "Multi-line flow scalars", passed); + int passed = 0; + int total = 0; + RunSpecTest(&Spec::SeqScalars, "2.1", "Sequence of Scalars", passed, total); + RunSpecTest(&Spec::MappingScalarsToScalars, "2.2", "Mapping Scalars to Scalars", passed, total); + RunSpecTest(&Spec::MappingScalarsToSequences, "2.3", "Mapping Scalars to Sequences", passed, total); + RunSpecTest(&Spec::SequenceOfMappings, "2.4", "Sequence of Mappings", passed, total); + RunSpecTest(&Spec::SequenceOfSequences, "2.5", "Sequence of Sequences", passed, total); + RunSpecTest(&Spec::MappingOfMappings, "2.6", "Mapping of Mappings", passed, total); + RunSpecTest(&Spec::TwoDocumentsInAStream, "2.7", "Two Documents in a Stream", passed, total); + RunSpecTest(&Spec::PlayByPlayFeed, "2.8", "Play by Play Feed from a Game", passed, total); + RunSpecTest(&Spec::SingleDocumentWithTwoComments, "2.9", "Single Document with Two Comments", passed, total); + RunSpecTest(&Spec::SimpleAnchor, "2.10", "Node for \"Sammy Sosa\" appears twice in this document", passed, total); + RunSpecTest(&Spec::MappingBetweenSequences, "2.11", "Mapping between Sequences", passed, total); + RunSpecTest(&Spec::CompactNestedMapping, "2.12", "Compact Nested Mapping", passed, total); + RunSpecTest(&Spec::InLiteralsNewlinesArePreserved, "2.13", "In literals, newlines are preserved", passed, total); + RunSpecTest(&Spec::InFoldedScalarsNewlinesBecomeSpaces, "2.14", "In folded scalars, newlines become spaces", passed, total); + RunSpecTest(&Spec::FoldedNewlinesArePreservedForMoreIndentedAndBlankLines, "2.15", "Folded newlines are preserved for \"more indented\" and blank lines", passed, total); + RunSpecTest(&Spec::IndentationDeterminesScope, "2.16", "Indentation determines scope", passed, total); + RunSpecTest(&Spec::QuotedScalars, "2.17", "Quoted scalars", passed, total); + RunSpecTest(&Spec::MultiLineFlowScalars, "2.18", "Multi-line flow scalars", passed, total); - RunSpecTest(&Spec::Invoice, "2.27", "Invoice", passed); - RunSpecTest(&Spec::LogFile, "2.28", "Log File", passed); + RunSpecTest(&Spec::Invoice, "2.27", "Invoice", passed, total); + RunSpecTest(&Spec::LogFile, "2.28", "Log File", passed, total); - RunSpecTest(&Spec::BlockStructureIndicators, "5.3", "Block Structure Indicators", passed); - RunSpecTest(&Spec::FlowStructureIndicators, "5.4", "Flow Structure Indicators", passed); - RunSpecTest(&Spec::NodePropertyIndicators, "5.6", "Node Property Indicators", passed); - RunSpecTest(&Spec::BlockScalarIndicators, "5.7", "Block Scalar Indicators", passed); - RunSpecTest(&Spec::QuotedScalarIndicators, "5.8", "Quoted Scalar Indicators", passed); - RunSpecTest(&Spec::LineBreakCharacters, "5.11", "Line Break Characters", passed); - RunSpecTest(&Spec::TabsAndSpaces, "5.12", "Tabs and Spaces", passed); - RunSpecTest(&Spec::EscapedCharacters, "5.13", "Escaped Characters", passed); - RunSpecTest(&Spec::InvalidEscapedCharacters, "5.14", "Invalid Escaped Characters", passed); + RunSpecTest(&Spec::BlockStructureIndicators, "5.3", "Block Structure Indicators", passed, total); + RunSpecTest(&Spec::FlowStructureIndicators, "5.4", "Flow Structure Indicators", passed, total); + RunSpecTest(&Spec::NodePropertyIndicators, "5.6", "Node Property Indicators", passed, total); + RunSpecTest(&Spec::BlockScalarIndicators, "5.7", "Block Scalar Indicators", passed, total); + RunSpecTest(&Spec::QuotedScalarIndicators, "5.8", "Quoted Scalar Indicators", passed, total); + RunSpecTest(&Spec::LineBreakCharacters, "5.11", "Line Break Characters", passed, total); + RunSpecTest(&Spec::TabsAndSpaces, "5.12", "Tabs and Spaces", passed, total); + RunSpecTest(&Spec::EscapedCharacters, "5.13", "Escaped Characters", passed, total); + RunSpecTest(&Spec::InvalidEscapedCharacters, "5.14", "Invalid Escaped Characters", passed, total); - RunSpecTest(&Spec::IndentationSpaces, "6.1", "Indentation Spaces", passed); - RunSpecTest(&Spec::IndentationIndicators, "6.2", "Indentation Indicators", passed); - RunSpecTest(&Spec::SeparationSpaces, "6.3", "Separation Spaces", passed); - RunSpecTest(&Spec::LinePrefixes, "6.4", "Line Prefixes", passed); - RunSpecTest(&Spec::EmptyLines, "6.5", "Empty Lines", passed); - return passed; + RunSpecTest(&Spec::IndentationSpaces, "6.1", "Indentation Spaces", passed, total); + RunSpecTest(&Spec::IndentationIndicators, "6.2", "Indentation Indicators", passed, total); + RunSpecTest(&Spec::SeparationSpaces, "6.3", "Separation Spaces", passed, total); + RunSpecTest(&Spec::LinePrefixes, "6.4", "Line Prefixes", passed, total); + RunSpecTest(&Spec::EmptyLines, "6.5", "Empty Lines", passed, total); + + std::cout << "Spec tests: " << passed << "/" << total << " passed\n"; + return passed == total; } } diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp index f95ba12..492a5d1 100644 --- a/yaml-reader/tests.cpp +++ b/yaml-reader/tests.cpp @@ -1,4 +1,6 @@ #include "tests.h" +#include "emittertests.h" +#include "parsertests.h" #include "spectests.h" #include "yaml.h" #include @@ -23,367 +25,5 @@ namespace Test if(passed) std::cout << "All tests passed!\n"; } - - //////////////////////////////////////////////////////////////////////////////////////// - // Parser tests - - namespace { - void RunScalarParserTest(void (*test)(std::string&, std::string&), const std::string& name, bool& passed) { - std::string error; - std::string inputScalar, desiredOutput; - std::string output; - bool ok = true; - try { - test(inputScalar, desiredOutput); - std::stringstream stream(inputScalar); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - doc >> output; - } catch(const YAML::Exception& e) { - ok = false; - error = e.msg; - } - if(ok && output == desiredOutput) { - std::cout << "Parser test passed: " << name << "\n"; - } else { - passed = false; - std::cout << "Parser test failed: " << name << "\n"; - if(error != "") - std::cout << "Caught exception: " << error << "\n"; - else { - std::cout << "Output:\n" << output << "<<<\n"; - std::cout << "Desired output:\n" << desiredOutput << "<<<\n"; - } - } - } - - void RunParserTest(bool (*test)(), const std::string& name, bool& passed) { - std::string error; - bool ok = true; - try { - ok = test(); - } catch(const YAML::Exception& e) { - ok = false; - error = e.msg; - } - if(ok) { - std::cout << "Parser test passed: " << name << "\n"; - } else { - passed = false; - std::cout << "Parser test failed: " << name << "\n"; - if(error != "") - std::cout << "Caught exception: " << error << "\n"; - } - } - - typedef void (*EncodingFn)(std::ostream&, int); - - inline char Byte(int ch) - { - return static_cast(static_cast(static_cast(ch))); - } - - void EncodeToUtf8(std::ostream& stream, int ch) - { - if (ch <= 0x7F) - { - stream << Byte(ch); - } - else if (ch <= 0x7FF) - { - stream << Byte(0xC0 | (ch >> 6)); - stream << Byte(0x80 | (ch & 0x3F)); - } - else if (ch <= 0xFFFF) - { - stream << Byte(0xE0 | (ch >> 12)); - stream << Byte(0x80 | ((ch >> 6) & 0x3F)); - stream << Byte(0x80 | (ch & 0x3F)); - } - else if (ch <= 0x1FFFFF) - { - stream << Byte(0xF0 | (ch >> 18)); - stream << Byte(0x80 | ((ch >> 12) & 0x3F)); - stream << Byte(0x80 | ((ch >> 6) & 0x3F)); - stream << Byte(0x80 | (ch & 0x3F)); - } - } - - bool SplitUtf16HighChar(std::ostream& stream, EncodingFn encoding, int ch) - { - int biasedValue = ch - 0x10000; - if (biasedValue < 0) - { - return false; - } - int high = 0xD800 | (biasedValue >> 10); - int low = 0xDC00 | (biasedValue & 0x3FF); - encoding(stream, high); - encoding(stream, low); - return true; - } - - void EncodeToUtf16LE(std::ostream& stream, int ch) - { - if (!SplitUtf16HighChar(stream, &EncodeToUtf16LE, ch)) - { - stream << Byte(ch & 0xFF) << Byte(ch >> 8); - } - } - - void EncodeToUtf16BE(std::ostream& stream, int ch) - { - if (!SplitUtf16HighChar(stream, &EncodeToUtf16BE, ch)) - { - stream << Byte(ch >> 8) << Byte(ch & 0xFF); - } - } - - void EncodeToUtf32LE(std::ostream& stream, int ch) - { - stream << Byte(ch & 0xFF) << Byte((ch >> 8) & 0xFF) - << Byte((ch >> 16) & 0xFF) << Byte((ch >> 24) & 0xFF); - } - - void EncodeToUtf32BE(std::ostream& stream, int ch) - { - stream << Byte((ch >> 24) & 0xFF) << Byte((ch >> 16) & 0xFF) - << Byte((ch >> 8) & 0xFF) << Byte(ch & 0xFF); - } - - class EncodingTester - { - public: - EncodingTester(EncodingFn encoding, bool declareEncoding) - { - if (declareEncoding) - { - encoding(m_yaml, 0xFEFF); - } - - AddEntry(encoding, 0x0021, 0x007E); // Basic Latin - AddEntry(encoding, 0x00A1, 0x00FF); // Latin-1 Supplement - AddEntry(encoding, 0x0660, 0x06FF); // Arabic (largest contiguous block) - - // CJK unified ideographs (multiple lines) - AddEntry(encoding, 0x4E00, 0x4EFF); - AddEntry(encoding, 0x4F00, 0x4FFF); - AddEntry(encoding, 0x5000, 0x51FF); // 512 character line - AddEntry(encoding, 0x5200, 0x54FF); // 768 character line - AddEntry(encoding, 0x5500, 0x58FF); // 1024 character line - - AddEntry(encoding, 0x103A0, 0x103C3); // Old Persian - - m_yaml.seekg(0, std::ios::beg); - } - - std::istream& stream() {return m_yaml;} - const std::vector& entries() {return m_entries;} - - private: - std::stringstream m_yaml; - std::vector m_entries; - - void AddEntry(EncodingFn encoding, int startCh, int endCh) - { - encoding(m_yaml, '-'); - encoding(m_yaml, ' '); - encoding(m_yaml, '|'); - encoding(m_yaml, '\n'); - encoding(m_yaml, ' '); - encoding(m_yaml, ' '); - - std::stringstream entry; - for (int ch = startCh; ch <= endCh; ++ch) - { - encoding(m_yaml, ch); - EncodeToUtf8(entry, ch); - } - encoding(m_yaml, '\n'); - - m_entries.push_back(entry.str()); - } - }; - - void RunEncodingTest(EncodingFn encoding, bool declareEncoding, const std::string& name, bool& passed) - { - EncodingTester tester(encoding, declareEncoding); - std::string error; - bool ok = true; - try { - YAML::Parser parser(tester.stream()); - YAML::Node doc; - parser.GetNextDocument(doc); - - YAML::Iterator itNode = doc.begin(); - std::vector::const_iterator itEntry = tester.entries().begin(); - for (; (itNode != doc.end()) && (itEntry != tester.entries().end()); ++itNode, ++itEntry) - { - std::string stScalarValue; - if (!itNode->GetScalar(stScalarValue) && (stScalarValue == *itEntry)) - { - break; - } - } - - if ((itNode != doc.end()) || (itEntry != tester.entries().end())) - { - ok = false; - } - } catch(const YAML::Exception& e) { - ok = false; - error = e.msg; - } - if(ok) { - std::cout << "Parser test passed: " << name << "\n"; - } else { - passed = false; - std::cout << "Parser test failed: " << name << "\n"; - if(error != "") - std::cout << "Caught exception: " << error << "\n"; - } - } - } - - bool RunParserTests() - { - bool passed = true; - RunScalarParserTest(&Parser::SimpleScalar, "simple scalar", passed); - RunScalarParserTest(&Parser::MultiLineScalar, "multi-line scalar", passed); - RunScalarParserTest(&Parser::LiteralScalar, "literal scalar", passed); - RunScalarParserTest(&Parser::FoldedScalar, "folded scalar", passed); - RunScalarParserTest(&Parser::ChompedFoldedScalar, "chomped folded scalar", passed); - RunScalarParserTest(&Parser::ChompedLiteralScalar, "chomped literal scalar", passed); - RunScalarParserTest(&Parser::FoldedScalarWithIndent, "folded scalar with indent", passed); - RunScalarParserTest(&Parser::ColonScalar, "colon scalar", passed); - RunScalarParserTest(&Parser::QuotedScalar, "quoted scalar", passed); - RunScalarParserTest(&Parser::CommaScalar, "comma scalar", passed); - RunScalarParserTest(&Parser::DashScalar, "dash scalar", passed); - RunScalarParserTest(&Parser::URLScalar, "url scalar", passed); - - RunParserTest(&Parser::SimpleSeq, "simple seq", passed); - RunParserTest(&Parser::SimpleMap, "simple map", passed); - RunParserTest(&Parser::FlowSeq, "flow seq", passed); - RunParserTest(&Parser::FlowMap, "flow map", passed); - RunParserTest(&Parser::FlowMapWithOmittedKey, "flow map with omitted key", passed); - RunParserTest(&Parser::FlowMapWithOmittedValue, "flow map with omitted value", passed); - RunParserTest(&Parser::FlowMapWithSoloEntry, "flow map with solo entry", passed); - RunParserTest(&Parser::FlowMapEndingWithSoloEntry, "flow map ending with solo entry", passed); - RunParserTest(&Parser::QuotedSimpleKeys, "quoted simple keys", passed); - RunParserTest(&Parser::CompressedMapAndSeq, "compressed map and seq", passed); - RunParserTest(&Parser::NullBlockSeqEntry, "null block seq entry", passed); - RunParserTest(&Parser::NullBlockMapKey, "null block map key", passed); - RunParserTest(&Parser::NullBlockMapValue, "null block map value", passed); - RunParserTest(&Parser::SimpleAlias, "simple alias", passed); - RunParserTest(&Parser::AliasWithNull, "alias with null", passed); - RunParserTest(&Parser::AnchorInSimpleKey, "anchor in simple key", passed); - RunParserTest(&Parser::AliasAsSimpleKey, "alias as simple key", passed); - RunParserTest(&Parser::ExplicitDoc, "explicit doc", passed); - RunParserTest(&Parser::MultipleDocs, "multiple docs", passed); - RunParserTest(&Parser::ExplicitEndDoc, "explicit end doc", passed); - RunParserTest(&Parser::MultipleDocsWithSomeExplicitIndicators, "multiple docs with some explicit indicators", passed); - - RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed); - RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed); - RunEncodingTest(&EncodeToUtf16LE, false, "UTF-16LE, no BOM", passed); - RunEncodingTest(&EncodeToUtf16LE, true, "UTF-16LE with BOM", passed); - RunEncodingTest(&EncodeToUtf16BE, false, "UTF-16BE, no BOM", passed); - RunEncodingTest(&EncodeToUtf16BE, true, "UTF-16BE with BOM", passed); - RunEncodingTest(&EncodeToUtf32LE, false, "UTF-32LE, no BOM", passed); - RunEncodingTest(&EncodeToUtf32LE, true, "UTF-32LE with BOM", passed); - RunEncodingTest(&EncodeToUtf32BE, false, "UTF-32BE, no BOM", passed); - RunEncodingTest(&EncodeToUtf32BE, true, "UTF-32BE with BOM", passed); - return passed; - } - - //////////////////////////////////////////////////////////////////////////////////////// - // Emitter tests - - namespace { - void RunEmitterTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, bool& passed) { - YAML::Emitter out; - std::string desiredOutput; - test(out, desiredOutput); - std::string output = out.c_str(); - - if(output == desiredOutput) { - std::cout << "Emitter test passed: " << name << "\n"; - } else { - passed = false; - std::cout << "Emitter test failed: " << name << "\n"; - std::cout << "Output:\n"; - std::cout << output << "<<<\n"; - std::cout << "Desired output:\n"; - std::cout << desiredOutput << "<<<\n"; - } - } - - void RunEmitterErrorTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, bool& passed) { - YAML::Emitter out; - std::string desiredError; - test(out, desiredError); - std::string lastError = out.GetLastError(); - if(!out.good() && lastError == desiredError) { - std::cout << "Emitter test passed: " << name << "\n"; - } else { - passed = false; - std::cout << "Emitter test failed: " << name << "\n"; - if(out.good()) - std::cout << "No error detected\n"; - else - std::cout << "Detected error: " << lastError << "\n"; - std::cout << "Expected error: " << desiredError << "\n"; - } - } - } - - bool RunEmitterTests() - { - bool passed = true; - RunEmitterTest(&Emitter::SimpleScalar, "simple scalar", passed); - RunEmitterTest(&Emitter::SimpleSeq, "simple seq", passed); - RunEmitterTest(&Emitter::SimpleFlowSeq, "simple flow seq", passed); - RunEmitterTest(&Emitter::EmptyFlowSeq, "empty flow seq", passed); - RunEmitterTest(&Emitter::NestedBlockSeq, "nested block seq", passed); - RunEmitterTest(&Emitter::NestedFlowSeq, "nested flow seq", passed); - RunEmitterTest(&Emitter::SimpleMap, "simple map", passed); - RunEmitterTest(&Emitter::SimpleFlowMap, "simple flow map", passed); - RunEmitterTest(&Emitter::MapAndList, "map and list", passed); - RunEmitterTest(&Emitter::ListAndMap, "list and map", passed); - RunEmitterTest(&Emitter::NestedBlockMap, "nested block map", passed); - RunEmitterTest(&Emitter::NestedFlowMap, "nested flow map", passed); - RunEmitterTest(&Emitter::MapListMix, "map list mix", passed); - RunEmitterTest(&Emitter::SimpleLongKey, "simple long key", passed); - RunEmitterTest(&Emitter::SingleLongKey, "single long key", passed); - RunEmitterTest(&Emitter::ComplexLongKey, "complex long key", passed); - RunEmitterTest(&Emitter::AutoLongKey, "auto long key", passed); - RunEmitterTest(&Emitter::ScalarFormat, "scalar format", passed); - RunEmitterTest(&Emitter::AutoLongKeyScalar, "auto long key scalar", passed); - RunEmitterTest(&Emitter::LongKeyFlowMap, "long key flow map", passed); - RunEmitterTest(&Emitter::BlockMapAsKey, "block map as key", passed); - RunEmitterTest(&Emitter::AliasAndAnchor, "alias and anchor", passed); - RunEmitterTest(&Emitter::AliasAndAnchorWithNull, "alias and anchor with null", passed); - RunEmitterTest(&Emitter::ComplexDoc, "complex doc", passed); - RunEmitterTest(&Emitter::STLContainers, "STL containers", passed); - RunEmitterTest(&Emitter::SimpleComment, "simple comment", passed); - RunEmitterTest(&Emitter::MultiLineComment, "multi-line comment", passed); - RunEmitterTest(&Emitter::ComplexComments, "complex comments", passed); - RunEmitterTest(&Emitter::Indentation, "indentation", passed); - RunEmitterTest(&Emitter::SimpleGlobalSettings, "simple global settings", passed); - RunEmitterTest(&Emitter::ComplexGlobalSettings, "complex global settings", passed); - RunEmitterTest(&Emitter::Null, "null", passed); - - RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed); - RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed); - RunEmitterErrorTest(&Emitter::BadSingleQuoted, "bad single quoted string", passed); - RunEmitterErrorTest(&Emitter::InvalidAnchor, "invalid anchor", passed); - RunEmitterErrorTest(&Emitter::InvalidAlias, "invalid alias", passed); - RunEmitterErrorTest(&Emitter::MissingKey, "missing key", passed); - RunEmitterErrorTest(&Emitter::MissingValue, "missing value", passed); - RunEmitterErrorTest(&Emitter::UnexpectedKey, "unexpected key", passed); - RunEmitterErrorTest(&Emitter::UnexpectedValue, "unexpected value", passed); - return passed; - } - } + diff --git a/yaml-reader/tests.h b/yaml-reader/tests.h index bcdc33e..0d39007 100644 --- a/yaml-reader/tests.h +++ b/yaml-reader/tests.h @@ -5,13 +5,8 @@ #include -namespace YAML { class Emitter; } - namespace Test { void RunAll(); - - bool RunParserTests(); - bool RunEmitterTests(); namespace Parser { // scalar tests @@ -51,53 +46,6 @@ namespace Test { bool ExplicitEndDoc(); bool MultipleDocsWithSomeExplicitIndicators(); } - - namespace Emitter { - // correct emitting - void SimpleScalar(YAML::Emitter& out, std::string& desiredOutput); - void SimpleSeq(YAML::Emitter& out, std::string& desiredOutput); - void SimpleFlowSeq(YAML::Emitter& ouptut, std::string& desiredOutput); - void EmptyFlowSeq(YAML::Emitter& out, std::string& desiredOutput); - void NestedBlockSeq(YAML::Emitter& out, std::string& desiredOutput); - void NestedFlowSeq(YAML::Emitter& out, std::string& desiredOutput); - void SimpleMap(YAML::Emitter& out, std::string& desiredOutput); - void SimpleFlowMap(YAML::Emitter& out, std::string& desiredOutput); - void MapAndList(YAML::Emitter& out, std::string& desiredOutput); - void ListAndMap(YAML::Emitter& out, std::string& desiredOutput); - void NestedBlockMap(YAML::Emitter& out, std::string& desiredOutput); - void NestedFlowMap(YAML::Emitter& out, std::string& desiredOutput); - void MapListMix(YAML::Emitter& out, std::string& desiredOutput); - void SimpleLongKey(YAML::Emitter& out, std::string& desiredOutput); - void SingleLongKey(YAML::Emitter& out, std::string& desiredOutput); - void ComplexLongKey(YAML::Emitter& out, std::string& desiredOutput); - void AutoLongKey(YAML::Emitter& out, std::string& desiredOutput); - void ScalarFormat(YAML::Emitter& out, std::string& desiredOutput); - void AutoLongKeyScalar(YAML::Emitter& out, std::string& desiredOutput); - void LongKeyFlowMap(YAML::Emitter& out, std::string& desiredOutput); - void BlockMapAsKey(YAML::Emitter& out, std::string& desiredOutput); - void AliasAndAnchor(YAML::Emitter& out, std::string& desiredOutput); - void AliasAndAnchorWithNull(YAML::Emitter& out, std::string& desiredOutput); - void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput); - void STLContainers(YAML::Emitter& out, std::string& desiredOutput); - void SimpleComment(YAML::Emitter& out, std::string& desiredOutput); - void MultiLineComment(YAML::Emitter& out, std::string& desiredOutput); - void ComplexComments(YAML::Emitter& out, std::string& desiredOutput); - void Indentation(YAML::Emitter& out, std::string& desiredOutput); - void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput); - void ComplexGlobalSettings(YAML::Emitter& out, std::string& desiredOutput); - void Null(YAML::Emitter& out, std::string& desiredOutput); - - // incorrect emitting - void ExtraEndSeq(YAML::Emitter& out, std::string& desiredError); - void ExtraEndMap(YAML::Emitter& out, std::string& desiredError); - void BadSingleQuoted(YAML::Emitter& out, std::string& desiredError); - void InvalidAnchor(YAML::Emitter& out, std::string& desiredError); - void InvalidAlias(YAML::Emitter& out, std::string& desiredError); - void MissingKey(YAML::Emitter& out, std::string& desiredError); - void MissingValue(YAML::Emitter& out, std::string& desiredError); - void UnexpectedKey(YAML::Emitter& out, std::string& desiredError); - void UnexpectedValue(YAML::Emitter& out, std::string& desiredError); - } } #endif // TESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 From afe01a86bd52468661d8ba775e3c58eb454a25f2 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 7 Sep 2009 22:48:32 +0000 Subject: [PATCH 165/295] Fixed newlines in folded scalars bug --- src/scanscalar.cpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/scanscalar.cpp b/src/scanscalar.cpp index 7294ce9..5a38943 100644 --- a/src/scanscalar.cpp +++ b/src/scanscalar.cpp @@ -21,6 +21,8 @@ namespace YAML { bool foundNonEmptyLine = false, pastOpeningBreak = false; bool emptyLine = false, moreIndented = false; + int foldedNewlineCount = 0; + bool foldedNewlineStartedMoreIndented = false; std::string scalar; params.leadingSpaces = false; @@ -109,13 +111,27 @@ namespace YAML // was this an empty line? bool nextEmptyLine = Exp::Break.Matches(INPUT); bool nextMoreIndented = (INPUT.peek() == ' '); + if(params.fold && foldedNewlineCount == 0 && nextEmptyLine) + foldedNewlineStartedMoreIndented = moreIndented; // for block scalars, we always start with a newline, so we should ignore it (not fold or keep) if(pastOpeningBreak) { - if(params.fold && !emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented && INPUT.column() >= params.indent) - scalar += " "; - else + if(params.fold) { + if(!emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented && INPUT.column() >= params.indent) + scalar += " "; + else if(nextEmptyLine) + foldedNewlineCount++; + else + scalar += "\n"; + + if(!nextEmptyLine && foldedNewlineCount > 0) { + if(foldedNewlineStartedMoreIndented || nextMoreIndented) + scalar += std::string("\n", foldedNewlineCount); + foldedNewlineCount = 0; + } + } else { scalar += "\n"; + } } emptyLine = nextEmptyLine; From d38c4e60265363aae8d6fd8adfeab93d43a06459 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 7 Sep 2009 23:29:04 +0000 Subject: [PATCH 166/295] (Actually) fixed the folding newline bug, but it's a bit messy, and we don't accurately make the distinction between block folding and flow folding --- src/exp.cpp | 2 +- src/scanscalar.cpp | 5 ++-- yaml-reader/spectests.cpp | 62 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/src/exp.cpp b/src/exp.cpp index b5cb815..7f4256f 100644 --- a/src/exp.cpp +++ b/src/exp.cpp @@ -83,7 +83,7 @@ namespace YAML // now do the slash (we're not gonna check if it's a slash - you better pass one!) switch(ch) { - case '0': return std::string("\x00", 1); + case '0': return std::string(1, '\x00'); case 'a': return "\x07"; case 'b': return "\x08"; case 't': diff --git a/src/scanscalar.cpp b/src/scanscalar.cpp index 5a38943..3432653 100644 --- a/src/scanscalar.cpp +++ b/src/scanscalar.cpp @@ -110,7 +110,7 @@ namespace YAML // was this an empty line? bool nextEmptyLine = Exp::Break.Matches(INPUT); - bool nextMoreIndented = (INPUT.peek() == ' '); + bool nextMoreIndented = Exp::Blank.Matches(INPUT); if(params.fold && foldedNewlineCount == 0 && nextEmptyLine) foldedNewlineStartedMoreIndented = moreIndented; @@ -125,8 +125,9 @@ namespace YAML scalar += "\n"; if(!nextEmptyLine && foldedNewlineCount > 0) { + scalar += std::string(foldedNewlineCount - 1, '\n'); if(foldedNewlineStartedMoreIndented || nextMoreIndented) - scalar += std::string("\n", foldedNewlineCount); + scalar += "\n"; foldedNewlineCount = 0; } } else { diff --git a/yaml-reader/spectests.cpp b/yaml-reader/spectests.cpp index 1093a71..cd176a7 100644 --- a/yaml-reader/spectests.cpp +++ b/yaml-reader/spectests.cpp @@ -952,6 +952,65 @@ namespace Test { YAML_ASSERT(doc["Chomping"] == "Clipped empty lines\n"); return true; } + + // 6.6 + TEST LineFolding() + { + std::string input = + ">-\n" + " trimmed\n" + " \n" + " \n" + "\n" + " as\n" + " space"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc == "trimmed\n\n\nas space"); + return true; + } + + // 6.7 + TEST BlockFolding() + { + std::string input = + ">\n" + " foo \n" + " \n" + " \t bar\n" + "\n" + " baz\n"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc == "foo \n\n\t bar\n\nbaz\n"); + return true; + } + + // 6.8 + TEST FlowFolding() + { + std::string input = + "\"\n" + " foo \n" + " \n" + " \t bar\n" + "\n" + " baz\n" + "\""; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc == " foo\nbar\nbaz "); + return true; + } } bool RunSpecTests() @@ -995,6 +1054,9 @@ namespace Test { RunSpecTest(&Spec::SeparationSpaces, "6.3", "Separation Spaces", passed, total); RunSpecTest(&Spec::LinePrefixes, "6.4", "Line Prefixes", passed, total); RunSpecTest(&Spec::EmptyLines, "6.5", "Empty Lines", passed, total); + RunSpecTest(&Spec::LineFolding, "6.6", "Line Folding", passed, total); + RunSpecTest(&Spec::BlockFolding, "6.7", "Block Folding", passed, total); + RunSpecTest(&Spec::FlowFolding, "6.8", "Flow Folding", passed, total); std::cout << "Spec tests: " << passed << "/" << total << " passed\n"; return passed == total; From 1d52e037502eb66d40b90d94e9e465f8aca1818a Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 8 Sep 2009 04:16:45 +0000 Subject: [PATCH 167/295] Tests through 6.29, skipping directives and tags --- yaml-reader/spectests.cpp | 117 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/yaml-reader/spectests.cpp b/yaml-reader/spectests.cpp index cd176a7..11cafbf 100644 --- a/yaml-reader/spectests.cpp +++ b/yaml-reader/spectests.cpp @@ -1011,6 +1011,118 @@ namespace Test { YAML_ASSERT(doc == " foo\nbar\nbaz "); return true; } + + // 6.9 + TEST SeparatedComment() + { + std::string input = + "key: # Comment\n" + " value"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc["key"] == "value"); + return true; + } + + // 6.10 + TEST CommentLines() + { + std::string input = + " # Comment\n" + " \n" + "\n"; + std::stringstream stream(input); + YAML::Parser parser(stream); + + YAML_ASSERT(!parser); + return true; + } + + // 6.11 + TEST MultiLineComments() + { + std::string input = + "key: # Comment\n" + " # lines\n" + " value\n" + "\n"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc["key"] == "value"); + return true; + } + + struct StringMap { + typedef std::map Map; + Map _; + }; + + bool operator == (const StringMap& m, const StringMap& n) { + return m._ == n._; + } + + void operator >> (const YAML::Node& node, StringMap& m) { + m._.clear(); + for(YAML::Iterator it=node.begin();it!=node.end();++it) { + std::string key = it.first(); + std::string value = it.second(); + m._[key] = value; + } + } + + + // 6.12 + TEST SeparationSpacesII() + { + std::string input = + "{ first: Sammy, last: Sosa }:\n" + "# Statistics:\n" + " hr: # Home runs\n" + " 65\n" + " avg: # Average\n" + " 0.278"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + StringMap key; + key._["first"] = "Sammy"; + key._["last"] = "Sosa"; + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc[key].size() == 2); + YAML_ASSERT(doc[key]["hr"] == 65); + YAML_ASSERT(doc[key]["avg"] == "0.278"); + return true; + } + + // TODO: 6.13 - 6.17 directives + // TODO: 6.18 - 6.28 tags + + // 6.29 + TEST NodeAnchors() + { + std::string input = + "First occurrence: &anchor Value\n" + "Second occurrence: *anchor"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["First occurrence"] == "Value"); + YAML_ASSERT(doc["Second occurrence"] == "Value"); + return true; + } } bool RunSpecTests() @@ -1057,6 +1169,11 @@ namespace Test { RunSpecTest(&Spec::LineFolding, "6.6", "Line Folding", passed, total); RunSpecTest(&Spec::BlockFolding, "6.7", "Block Folding", passed, total); RunSpecTest(&Spec::FlowFolding, "6.8", "Flow Folding", passed, total); + RunSpecTest(&Spec::SeparatedComment, "6.9", "Separated Comment", passed, total); + RunSpecTest(&Spec::CommentLines, "6.10", "Comment Lines", passed, total); + RunSpecTest(&Spec::SeparationSpacesII, "6.11", "Separation Spaces", passed, total); + + RunSpecTest(&Spec::NodeAnchors, "6.29", "Node Anchors", passed, total); std::cout << "Spec tests: " << passed << "/" << total << " passed\n"; return passed == total; From e4540f2c2adbe6f16938c2646d1113b5c26761a9 Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 8 Sep 2009 05:24:06 +0000 Subject: [PATCH 168/295] Fixed flow folding, and made the separation slightly cleaner (but the whole scanscalar thing could use a major refactoring) --- src/scanscalar.cpp | 57 +++++++++++++++++++++++++++++++--------------- src/scanscalar.h | 5 ++-- src/scantoken.cpp | 6 ++--- 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/scanscalar.cpp b/src/scanscalar.cpp index 3432653..cdbdb60 100644 --- a/src/scanscalar.cpp +++ b/src/scanscalar.cpp @@ -19,7 +19,8 @@ namespace YAML // and different places in the above flow. std::string ScanScalar(Stream& INPUT, ScanScalarParams& params) { - bool foundNonEmptyLine = false, pastOpeningBreak = false; + bool foundNonEmptyLine = false; + bool pastOpeningBreak = (params.fold == FOLD_FLOW); bool emptyLine = false, moreIndented = false; int foldedNewlineCount = 0; bool foldedNewlineStartedMoreIndented = false; @@ -29,6 +30,8 @@ namespace YAML while(INPUT) { // ******************************** // Phase #1: scan until line ending + + std::size_t lastNonWhitespaceChar = scalar.size(); while(!params.end.Matches(INPUT) && !Exp::Break.Matches(INPUT)) { if(!INPUT) break; @@ -48,17 +51,22 @@ namespace YAML if(params.escape == '\\' && Exp::EscBreak.Matches(INPUT)) { int n = Exp::EscBreak.Match(INPUT); INPUT.eat(n); + lastNonWhitespaceChar = scalar.size(); continue; } // escape this? if(INPUT.peek() == params.escape) { scalar += Exp::Escape(INPUT); + lastNonWhitespaceChar = scalar.size(); continue; } // otherwise, just add the damn character - scalar += INPUT.get(); + char ch = INPUT.get(); + scalar += ch; + if(ch != ' ' && ch != '\t') + lastNonWhitespaceChar = scalar.size(); } // eof? if we're looking to eat something, then we throw @@ -79,7 +87,11 @@ namespace YAML INPUT.eat(n); break; } - + + // do we remove trailing whitespace? + if(params.fold == FOLD_FLOW) + scalar.erase(lastNonWhitespaceChar); + // ******************************** // Phase #2: eat line ending n = Exp::Break.Match(INPUT); @@ -111,27 +123,36 @@ namespace YAML // was this an empty line? bool nextEmptyLine = Exp::Break.Matches(INPUT); bool nextMoreIndented = Exp::Blank.Matches(INPUT); - if(params.fold && foldedNewlineCount == 0 && nextEmptyLine) + if(params.fold == FOLD_BLOCK && foldedNewlineCount == 0 && nextEmptyLine) foldedNewlineStartedMoreIndented = moreIndented; // for block scalars, we always start with a newline, so we should ignore it (not fold or keep) if(pastOpeningBreak) { - if(params.fold) { - if(!emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented && INPUT.column() >= params.indent) - scalar += " "; - else if(nextEmptyLine) - foldedNewlineCount++; - else + switch(params.fold) { + case DONT_FOLD: scalar += "\n"; - - if(!nextEmptyLine && foldedNewlineCount > 0) { - scalar += std::string(foldedNewlineCount - 1, '\n'); - if(foldedNewlineStartedMoreIndented || nextMoreIndented) + break; + case FOLD_BLOCK: + if(!emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented && INPUT.column() >= params.indent) + scalar += " "; + else if(nextEmptyLine) + foldedNewlineCount++; + else scalar += "\n"; - foldedNewlineCount = 0; - } - } else { - scalar += "\n"; + + if(!nextEmptyLine && foldedNewlineCount > 0) { + scalar += std::string(foldedNewlineCount - 1, '\n'); + if(foldedNewlineStartedMoreIndented || nextMoreIndented) + scalar += "\n"; + foldedNewlineCount = 0; + } + break; + case FOLD_FLOW: + if(nextEmptyLine) + scalar += "\n"; + else if(!emptyLine && !nextEmptyLine) + scalar += " "; + break; } } diff --git a/src/scanscalar.h b/src/scanscalar.h index 319a428..6f6f559 100644 --- a/src/scanscalar.h +++ b/src/scanscalar.h @@ -12,9 +12,10 @@ namespace YAML { enum CHOMP { STRIP = -1, CLIP, KEEP }; enum ACTION { NONE, BREAK, THROW }; + enum FOLD { DONT_FOLD, FOLD_BLOCK, FOLD_FLOW }; struct ScanScalarParams { - ScanScalarParams(): eatEnd(false), indent(0), detectIndent(false), eatLeadingWhitespace(0), escape(0), fold(false), + ScanScalarParams(): eatEnd(false), indent(0), detectIndent(false), eatLeadingWhitespace(0), escape(0), fold(DONT_FOLD), trimTrailingSpaces(0), chomp(CLIP), onDocIndicator(NONE), onTabInIndentation(NONE), leadingSpaces(false) {} // input: @@ -24,7 +25,7 @@ namespace YAML bool detectIndent; // should we try to autodetect the indent? bool eatLeadingWhitespace; // should we continue eating this delicious indentation after 'indent' spaces? char escape; // what character do we escape on (i.e., slash or single quote) (0 for none) - bool fold; // do we fold line ends? + FOLD fold; // how do we fold line ends? bool trimTrailingSpaces; // do we remove all trailing spaces (at the very end) CHOMP chomp; // do we strip, clip, or keep trailing newlines (at the very end) // Note: strip means kill all, clip means keep at most one, keep means keep all diff --git a/src/scantoken.cpp b/src/scantoken.cpp index cb56225..df8e11e 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -287,7 +287,7 @@ namespace YAML params.end = (InFlowContext() ? Exp::EndScalarInFlow : Exp::EndScalar) || (Exp::BlankOrBreak + Exp::Comment); params.eatEnd = false; params.indent = (InFlowContext() ? 0 : GetTopIndent() + 1); - params.fold = true; + params.fold = FOLD_BLOCK; params.eatLeadingWhitespace = true; params.trimTrailingSpaces = true; params.chomp = STRIP; @@ -327,7 +327,7 @@ namespace YAML params.eatEnd = true; params.escape = (single ? '\'' : '\\'); params.indent = 0; - params.fold = true; + params.fold = FOLD_FLOW; params.eatLeadingWhitespace = true; params.trimTrailingSpaces = false; params.chomp = CLIP; @@ -365,7 +365,7 @@ namespace YAML // eat block indicator ('|' or '>') Mark mark = INPUT.mark(); char indicator = INPUT.get(); - params.fold = (indicator == Keys::FoldedScalar); + params.fold = (indicator == Keys::FoldedScalar ? FOLD_BLOCK : DONT_FOLD); // eat chomping/indentation indicators params.chomp = CLIP; From 246d8993d2e1d61a6abcb7db1714f0fca02c5a1d Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 8 Sep 2009 05:35:39 +0000 Subject: [PATCH 169/295] More tests, found bug in implicit keys in flow sequence --- yaml-reader/spectests.cpp | 83 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/yaml-reader/spectests.cpp b/yaml-reader/spectests.cpp index 11cafbf..2eb3e8f 100644 --- a/yaml-reader/spectests.cpp +++ b/yaml-reader/spectests.cpp @@ -1123,6 +1123,84 @@ namespace Test { YAML_ASSERT(doc["Second occurrence"] == "Value"); return true; } + + // 7.1 + TEST AliasNodes() + { + std::string input = + "First occurrence: &anchor Foo\n" + "Second occurrence: *anchor\n" + "Override anchor: &anchor Bar\n" + "Reuse anchor: *anchor"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 4); + YAML_ASSERT(doc["First occurrence"] == "Foo"); + YAML_ASSERT(doc["Second occurrence"] == "Foo"); + YAML_ASSERT(doc["Override anchor"] == "Bar"); + YAML_ASSERT(doc["Reuse anchor"] == "Bar"); + return true; + } + + // 7.2 + TEST EmptyNodes() + { + std::string input = + "{\n" + " foo : !!str,\n" + " !!str : bar,\n" + "}"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["foo"] == ""); // TODO: check tag + YAML_ASSERT(doc[""] == "bar"); + return true; + } + + // 7.3 + TEST CompletelyEmptyNodes() + { + std::string input = + "{\n" + " ? foo :,\n" + " : bar,\n" + "}\n"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(IsNull(doc["foo"])); + YAML_ASSERT(doc[YAML::Null] == "bar"); + return true; + } + + // 7.4 + TEST DoubleQuotedImplicitKeys() + { + std::string input = + "\"implicit block key\" : [\n" + " \"implicit flow key\" : value,\n" + " ]"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc["implicit block key"].size() == 1); + YAML_ASSERT(doc["implicit block key"][0].size() == 1); + YAML_ASSERT(doc["implicit block key"][0]["implicit flow key"] == "value"); + return true; + } } bool RunSpecTests() @@ -1174,6 +1252,11 @@ namespace Test { RunSpecTest(&Spec::SeparationSpacesII, "6.11", "Separation Spaces", passed, total); RunSpecTest(&Spec::NodeAnchors, "6.29", "Node Anchors", passed, total); + + RunSpecTest(&Spec::AliasNodes, "7.1", "Alias Nodes", passed, total); + RunSpecTest(&Spec::EmptyNodes, "7.2", "Empty Nodes", passed, total); + RunSpecTest(&Spec::CompletelyEmptyNodes, "7.3", "Completely Empty Nodes", passed, total); + RunSpecTest(&Spec::DoubleQuotedImplicitKeys, "7.4", "Double Quoted Implicit Keys", passed, total); std::cout << "Spec tests: " << passed << "/" << total << " passed\n"; return passed == total; From 7b889b9f358759abca0b5f727b09bf99f36c321f Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 8 Sep 2009 20:57:18 +0000 Subject: [PATCH 170/295] Cleaned up the read template overloads (per litb's update); it seems the old version didn't compile in VS2008. Also updated the VS project files. --- include/nodereadimpl.h | 4 ++-- yaml-reader.vcproj | 16 ++++++++++++++++ yamlcpp.vcproj | 4 ++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/include/nodereadimpl.h b/include/nodereadimpl.h index 5beaa09..1ea7cf3 100644 --- a/include/nodereadimpl.h +++ b/include/nodereadimpl.h @@ -38,12 +38,12 @@ namespace YAML struct flag { char c[2]; }; flag Convert(...); - char (& operator,(flag, flag) )[1]; + int operator,(flag, flag); template void operator,(flag, T const&); - char (& operator,(char(&)[1], flag) )[1]; + char operator,(int, flag); } template diff --git a/yaml-reader.vcproj b/yaml-reader.vcproj index 84ad1d3..0e550f9 100644 --- a/yaml-reader.vcproj +++ b/yaml-reader.vcproj @@ -179,6 +179,10 @@ RelativePath=".\yaml-reader\parsertests.cpp" > + + @@ -189,6 +193,18 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + + + + + diff --git a/yamlcpp.vcproj b/yamlcpp.vcproj index 749ac8e..8673b8f 100644 --- a/yamlcpp.vcproj +++ b/yamlcpp.vcproj @@ -191,6 +191,10 @@ RelativePath=".\src\node.cpp" > + + From d957634c25cc633dc73050c17e3105ff6009458c Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 9 Sep 2009 01:37:23 +0000 Subject: [PATCH 171/295] Tagged version 0.2.2 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 556e9da..5d64b6f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ endif(CMAKE_COMPILER_IS_GNUCC) set(YAML_CPP_VERSION_MAJOR "0") set(YAML_CPP_VERSION_MINOR "2") -set(YAML_CPP_VERSION_PATCH "1") +set(YAML_CPP_VERSION_PATCH "2") set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}") enable_testing() From a20141bca7416e32b991edb616dc4f74c267cb83 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 16 Sep 2009 04:01:40 +0000 Subject: [PATCH 172/295] Patched for gcc version <= 3.3 (just fall back to original version of Node::Read) --- include/nodeimpl.h | 8 ++++---- include/nodereadimpl.h | 12 ++++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/include/nodeimpl.h b/include/nodeimpl.h index 3133977..e6cffc3 100644 --- a/include/nodeimpl.h +++ b/include/nodeimpl.h @@ -79,22 +79,22 @@ namespace YAML template inline bool operator == (const T& value, const Node& node) { - return value == node.Read(); + return value == node.operator T(); } template inline bool operator == (const Node& node, const T& value) { - return value == node.Read(); + return value == node.operator T(); } template inline bool operator != (const T& value, const Node& node) { - return value != node.Read(); + return value != node.operator T(); } template inline bool operator != (const Node& node, const T& value) { - return value != node.Read(); + return value != node.operator T(); } inline bool operator == (const char *value, const Node& node) { diff --git a/include/nodereadimpl.h b/include/nodereadimpl.h index 1ea7cf3..1f2341c 100644 --- a/include/nodereadimpl.h +++ b/include/nodereadimpl.h @@ -6,7 +6,18 @@ namespace YAML // (the goal is to call ConvertScalar if we can, and fall back to operator >> if not) // thanks to litb from stackoverflow.com // http://stackoverflow.com/questions/1386183/how-to-call-a-templated-function-if-it-exists-and-something-else-otherwise/1386390#1386390 + + // Note: this doesn't work on gcc 3.2, but does on gcc 3.4 and above. I'm not sure about 3.3. +#if (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ <= 3)) + // trick doesn't work? Just fall back to ConvertScalar. + // This means that we can't use any user-defined types as keys in a map + template + inline bool Node::Read(T& value) const { + return ConvertScalar(*this, value); + } +#else + // usual case: the trick! template struct read_impl; @@ -52,6 +63,7 @@ namespace YAML return read_impl::read(*this, value); } +#endif // done with trick // the main conversion function template From 60fce621e8268e059465c31215d579ce6a316840 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 16 Sep 2009 05:31:28 +0000 Subject: [PATCH 173/295] Modified old gcc version patch so it still uses the new Node::Read in Visual Studio. Also broke up the \uNNNN characters in the spec tests into \xNN-type strings. --- include/nodereadimpl.h | 2 +- yaml-reader/spectests.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/nodereadimpl.h b/include/nodereadimpl.h index 1f2341c..9ec024a 100644 --- a/include/nodereadimpl.h +++ b/include/nodereadimpl.h @@ -9,7 +9,7 @@ namespace YAML // Note: this doesn't work on gcc 3.2, but does on gcc 3.4 and above. I'm not sure about 3.3. -#if (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ <= 3)) +#if __GNUC__ && (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ <= 3)) // trick doesn't work? Just fall back to ConvertScalar. // This means that we can't use any user-defined types as keys in a map template diff --git a/yaml-reader/spectests.cpp b/yaml-reader/spectests.cpp index 2eb3e8f..009c690 100644 --- a/yaml-reader/spectests.cpp +++ b/yaml-reader/spectests.cpp @@ -477,7 +477,7 @@ namespace Test { parser.GetNextDocument(doc); YAML_ASSERT(doc.size() == 6); - YAML_ASSERT(doc["unicode"] == "Sosa did fine.\u263A"); + YAML_ASSERT(doc["unicode"] == "Sosa did fine.\xe2\x98\xba"); YAML_ASSERT(doc["control"] == "\b1998\t1999\t2000\n"); YAML_ASSERT(doc["hex esc"] == "\x0d\x0a is \r\n"); YAML_ASSERT(doc["single"] == "\"Howdy!\" he cried."); @@ -809,7 +809,7 @@ namespace Test { YAML::Node doc; parser.GetNextDocument(doc); - YAML_ASSERT(doc == "Fun with \x5C \x22 \x07 \x08 \x1B \x0C \x0A \x0D \x09 \x0B " + std::string("\x00", 1) + " \x20 \xA0 \x85 \u2028 \u2029 A A A"); + YAML_ASSERT(doc == "Fun with \x5C \x22 \x07 \x08 \x1B \x0C \x0A \x0D \x09 \x0B " + std::string("\x00", 1) + " \x20 \xA0 \x85 \xe2\x80\xa8 \xe2\x80\xa9 A A A"); return true; } From fb443b30560a3335e7f9848379bda9541093de77 Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 29 Sep 2009 18:25:11 +0000 Subject: [PATCH 174/295] Updated signature of Parser::GetNextDocument (issue 45) --- include/parser.h | 2 +- src/parser.cpp | 6 ++++-- util/parse.cpp | 5 ++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/include/parser.h b/include/parser.h index 0ccea84..f3a487c 100644 --- a/include/parser.h +++ b/include/parser.h @@ -25,7 +25,7 @@ namespace YAML operator bool() const; void Load(std::istream& in); - void GetNextDocument(Node& document); + bool GetNextDocument(Node& document); void PrintTokens(std::ostream& out); private: diff --git a/src/parser.cpp b/src/parser.cpp index 162364f..9cbfe32 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -33,7 +33,7 @@ namespace YAML // GetNextDocument // . Reads the next document in the queue (of tokens). // . Throws a ParserException on error. - void Parser::GetNextDocument(Node& document) + bool Parser::GetNextDocument(Node& document) { // clear node document.Clear(); @@ -43,7 +43,7 @@ namespace YAML // we better have some tokens in the queue if(m_pScanner->empty()) - return; + return false; // first eat doc start (optional) if(m_pScanner->peek().type == Token::DOC_START) @@ -58,6 +58,8 @@ namespace YAML // clear anchors from the scanner, which are no longer relevant m_pScanner->ClearAnchors(); + + return true; } // ParseDirectives diff --git a/util/parse.cpp b/util/parse.cpp index 56b1dc1..8a92576 100644 --- a/util/parse.cpp +++ b/util/parse.cpp @@ -11,9 +11,8 @@ int main(int argc, char **argv) std::istream& input = (argc > 1 ? fin : std::cin); try { YAML::Parser parser(input); - while(parser) { - YAML::Node doc; - parser.GetNextDocument(doc); + YAML::Node doc; + while(parser.GetNextDocument(doc)) { YAML::Emitter emitter; emitter << doc; std::cout << emitter.c_str() << "\n"; From 15d5b2b53365c0c0f69bd9802ad6e78e4630892a Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 7 Oct 2009 06:46:05 +0000 Subject: [PATCH 175/295] Fixed the emitter unicode output --- src/emitterutils.cpp | 102 ++++++++++++++++++++++++++++++++--- yaml-reader/emittertests.cpp | 8 +++ 2 files changed, 104 insertions(+), 6 deletions(-) diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index cddf5eb..f6ac3d3 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -40,6 +40,99 @@ namespace YAML return true; } + + unsigned ToUnsigned(char ch) { return static_cast(static_cast(ch)); } + unsigned AdvanceAndGetNextChar(std::string::const_iterator& it, std::string::const_iterator end) { + std::string::const_iterator jt = it; + ++jt; + if(jt == end) + return 0; + + ++it; + return ToUnsigned(*it); + } + + std::string WriteUnicode(unsigned value) { + std::stringstream str; + // TODO: for the common escaped characters, give their usual symbol + if(value <= 0xFF) + str << "\\x" << std::hex << std::setfill('0') << std::setw(2) << value; + else if(value <= 0xFFFF) + str << "\\u" << std::hex << std::setfill('0') << std::setw(4) << value; + else + str << "\\U" << std::hex << std::setfill('0') << std::setw(8) << value; + return str.str(); + } + + std::string WriteSingleByte(unsigned ch) { + return WriteUnicode(ch); + } + + std::string WriteTwoBytes(unsigned ch, unsigned ch1) { + // Note: if no second byte is provided (signalled by ch1 == 0) + // then we just write the first one as a single byte. + // Should we throw an error instead? Or write something else? + // (The same question goes for the other WriteNBytes functions) + if(ch1 == 0) + return WriteSingleByte(ch); + + unsigned value = ((ch - 0xC0) << 6) + (ch1 - 0x80); + return WriteUnicode(value); + } + + std::string WriteThreeBytes(unsigned ch, unsigned ch1, unsigned ch2) { + if(ch1 == 0) + return WriteSingleByte(ch); + if(ch2 == 0) + return WriteSingleByte(ch) + WriteSingleByte(ch1); + + unsigned value = ((ch - 0xE0) << 12) + ((ch1 - 0x80) << 6) + (ch2 - 0x80); + return WriteUnicode(value); + } + + std::string WriteFourBytes(unsigned ch, unsigned ch1, unsigned ch2, unsigned ch3) { + if(ch1 == 0) + return WriteSingleByte(ch); + if(ch2 == 0) + return WriteSingleByte(ch) + WriteSingleByte(ch1); + if(ch3 == 0) + return WriteSingleByte(ch) + WriteSingleByte(ch1) + WriteSingleByte(ch2); + + unsigned value = ((ch - 0xF0) << 18) + ((ch1 - 0x80) << 12) + ((ch2 - 0x80) << 6) + (ch3 - 0x80); + return WriteUnicode(value); + } + + // WriteNonPrintable + // . Writes the next UTF-8 code point to the stream + std::string::const_iterator WriteNonPrintable(ostream& out, std::string::const_iterator start, std::string::const_iterator end) { + std::string::const_iterator it = start; + unsigned ch = ToUnsigned(*it); + if(ch <= 0xC1) { + // this may include invalid first characters (0x80 - 0xBF) + // or "overlong" UTF-8 (0xC0 - 0xC1) + // We just copy them as bytes + // TODO: should we do something else? throw an error? + out << WriteSingleByte(ch); + return start; + } else if(ch <= 0xDF) { + unsigned ch1 = AdvanceAndGetNextChar(it, end); + out << WriteTwoBytes(ch, ch1); + return it; + } else if(ch <= 0xEF) { + unsigned ch1 = AdvanceAndGetNextChar(it, end); + unsigned ch2 = AdvanceAndGetNextChar(it, end); + out << WriteThreeBytes(ch, ch1, ch2); + return it; + } else { + unsigned ch1 = AdvanceAndGetNextChar(it, end); + unsigned ch2 = AdvanceAndGetNextChar(it, end); + unsigned ch3 = AdvanceAndGetNextChar(it, end); + out << WriteFourBytes(ch, ch1, ch2, ch3); + return it; + } + + return start; + } } bool WriteString(ostream& out, const std::string& str, bool inFlow) @@ -71,8 +164,8 @@ namespace YAML bool WriteDoubleQuotedString(ostream& out, const std::string& str) { out << "\""; - for(std::size_t i=0;i(static_cast(ch)); - out << str.str(); + it = WriteNonPrintable(out, it, str.end()); } } out << "\""; diff --git a/yaml-reader/emittertests.cpp b/yaml-reader/emittertests.cpp index 9af202f..c3209b2 100644 --- a/yaml-reader/emittertests.cpp +++ b/yaml-reader/emittertests.cpp @@ -447,6 +447,13 @@ namespace Test desiredOutput = "- ~\n-\n null value: ~\n ~: null key"; } + + void Unicode(YAML::Emitter& out, std::string& desiredOutput) + { + out << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; + + desiredOutput = "\"$ \\xa2 \\u20ac \\U00024b62\""; + } //////////////////////////////////////////////////////////////////////////////////////////////////////// // incorrect emitting @@ -609,6 +616,7 @@ namespace Test RunEmitterTest(&Emitter::SimpleGlobalSettings, "simple global settings", passed, total); RunEmitterTest(&Emitter::ComplexGlobalSettings, "complex global settings", passed, total); RunEmitterTest(&Emitter::Null, "null", passed, total); + RunEmitterTest(&Emitter::Unicode, "unicode", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total); From 41a776b3974cd1f95c8719579a2b496e829c59b3 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 8 Oct 2009 21:05:56 +0000 Subject: [PATCH 176/295] Refactored the UTF-8 emitting --- src/emitterutils.cpp | 158 +++++++++++++++++++++++++------------------ 1 file changed, 91 insertions(+), 67 deletions(-) diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index f6ac3d3..f4b7a57 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -5,6 +5,7 @@ #include "stringsource.h" #include #include +#include namespace YAML { @@ -41,17 +42,11 @@ namespace YAML return true; } - unsigned ToUnsigned(char ch) { return static_cast(static_cast(ch)); } - unsigned AdvanceAndGetNextChar(std::string::const_iterator& it, std::string::const_iterator end) { - std::string::const_iterator jt = it; - ++jt; - if(jt == end) - return 0; - - ++it; - return ToUnsigned(*it); - } + typedef unsigned char byte; + byte ToByte(char ch) { return static_cast(ch); } + typedef std::string::const_iterator StrIter; + std::string WriteUnicode(unsigned value) { std::stringstream str; // TODO: for the common escaped characters, give their usual symbol @@ -64,74 +59,101 @@ namespace YAML return str.str(); } - std::string WriteSingleByte(unsigned ch) { - return WriteUnicode(ch); + // GetBytesToRead + // . Returns the length of the UTF-8 sequence starting with 'signal' + int GetBytesToRead(byte signal) { + if(signal <= 0x7F) // ASCII + return 1; + else if(signal <= 0xBF) // invalid first characters + return 0; + else if(signal <= 0xDF) // Note: this allows "overlong" UTF8 (0xC0 - 0xC1) to pass unscathed. OK? + return 2; + else if(signal <= 0xEF) + return 3; + else + return 4; } - std::string WriteTwoBytes(unsigned ch, unsigned ch1) { - // Note: if no second byte is provided (signalled by ch1 == 0) - // then we just write the first one as a single byte. - // Should we throw an error instead? Or write something else? - // (The same question goes for the other WriteNBytes functions) - if(ch1 == 0) - return WriteSingleByte(ch); - - unsigned value = ((ch - 0xC0) << 6) + (ch1 - 0x80); - return WriteUnicode(value); + // ReadBytes + // . Reads the next 'bytesToRead', if we can. + // . Returns zero if we fail, otherwise fills the byte buffer with + // the data and returns the number of bytes read. + int ReadBytes(byte bytes[4], StrIter start, StrIter end, int bytesToRead) { + for(int i=0;i= 1) + it += (bytesRead - 1); } } out << "\""; From 06b8d4bacfea45bc6eccd060293b43ec3c08b071 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 12 Oct 2009 05:21:00 +0000 Subject: [PATCH 177/295] Patched for optional building of tests and tools --- CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d64b6f..7ed2297 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,8 @@ set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML enable_testing() +option(YAML_CPP_BUILD_TOOLS "Enables or disables yaml-reader and parse tools" true) + if(WIN32) set(_library_dir bin) # .dll are in PATH, like executables else(WIN32) @@ -64,5 +66,7 @@ if(UNIX) install(FILES ${PC_FILE} DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) endif(UNIX) -add_subdirectory (yaml-reader) -add_subdirectory (util) +if(YAML_CPP_BUILD_TOOLS) + add_subdirectory (yaml-reader) + add_subdirectory (util) +endif(YAML_CPP_BUILD_TOOLS) From dd29c8181a5951288292f562018037cea69ccd89 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 19 Oct 2009 22:32:26 +0000 Subject: [PATCH 178/295] Update CMakeLists.txt to append, not overwrite CMAKE_CXX_FLAGS --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ed2297..6116c27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ if(IPHONE) endif(IPHONE) if(CMAKE_COMPILER_IS_GNUCC) - set(CMAKE_CXX_FLAGS "-O2 -Wall -pedantic -Wextra") + set(CMAKE_CXX_FLAGS "-O2 -Wall -pedantic -Wextra ${CMAKE_CXX_FLAGS}") endif(CMAKE_COMPILER_IS_GNUCC) set(YAML_CPP_VERSION_MAJOR "0") From afc7c1088d1a50a2d437d67db98face52c2ffb26 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 19 Oct 2009 22:40:46 +0000 Subject: [PATCH 179/295] Added default constructor to Parser, and cleaned it up a bit --- include/parser.h | 16 +++++++--------- src/parser.cpp | 14 ++++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/include/parser.h b/include/parser.h index f3a487c..9f24916 100644 --- a/include/parser.h +++ b/include/parser.h @@ -4,21 +4,24 @@ #define PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#include "node.h" +#include "parserstate.h" +#include "noncopyable.h" #include #include #include #include -#include "node.h" -#include "parserstate.h" +#include namespace YAML { class Scanner; struct Token; - class Parser + class Parser: private noncopyable { public: + Parser(); Parser(std::istream& in); ~Parser(); @@ -35,12 +38,7 @@ namespace YAML void HandleTagDirective(Token *pToken); private: - // can't copy this - Parser(const Parser&) {} - Parser& operator = (const Parser&) { return *this; } - - private: - Scanner *m_pScanner; + std::auto_ptr m_pScanner; ParserState m_state; }; } diff --git a/src/parser.cpp b/src/parser.cpp index 9cbfe32..283bb94 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -8,25 +8,27 @@ namespace YAML { - Parser::Parser(std::istream& in): m_pScanner(0) + Parser::Parser() + { + } + + Parser::Parser(std::istream& in) { Load(in); } Parser::~Parser() { - delete m_pScanner; } Parser::operator bool() const { - return !m_pScanner->empty(); + return m_pScanner.get() && !m_pScanner->empty(); } void Parser::Load(std::istream& in) { - delete m_pScanner; - m_pScanner = new Scanner(in); + m_pScanner.reset(new Scanner(in)); m_state.Reset(); } @@ -50,7 +52,7 @@ namespace YAML m_pScanner->pop(); // now parse our root node - document.Parse(m_pScanner, m_state); + document.Parse(m_pScanner.get(), m_state); // and finally eat any doc ends we see while(!m_pScanner->empty() && m_pScanner->peek().type == Token::DOC_END) From ae937a31d2f9f52037468403e9d543f061269ed9 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 19 Oct 2009 22:42:30 +0000 Subject: [PATCH 180/295] Fixed little bug in parser commit --- src/parser.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/parser.cpp b/src/parser.cpp index 283bb94..1709436 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -37,6 +37,9 @@ namespace YAML // . Throws a ParserException on error. bool Parser::GetNextDocument(Node& document) { + if(!m_pScanner.get()) + return false; + // clear node document.Clear(); @@ -130,6 +133,9 @@ namespace YAML void Parser::PrintTokens(std::ostream& out) { + if(!m_pScanner.get()) + return; + while(1) { if(m_pScanner->empty()) break; From 9a28c9178e17a1c35301eb15abaf44481853bb12 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 19 Oct 2009 23:31:11 +0000 Subject: [PATCH 181/295] Merged r270:HEAD of the emitting-unicode branch --- include/emitter.h | 1 + include/emittermanip.h | 4 + src/emitter.cpp | 12 +- src/emitterstate.cpp | 14 ++ src/emitterstate.h | 4 + src/emitterutils.cpp | 357 +++++++++++++++++++---------------- src/emitterutils.h | 4 +- src/exp.cpp | 4 +- src/exp.h | 7 +- yaml-reader/emittertests.cpp | 19 +- 10 files changed, 257 insertions(+), 169 deletions(-) diff --git a/include/emitter.h b/include/emitter.h index 055c9c7..d512bb8 100644 --- a/include/emitter.h +++ b/include/emitter.h @@ -29,6 +29,7 @@ namespace YAML const std::string GetLastError() const; // global setters + bool SetOutputCharset(EMITTER_MANIP value); bool SetStringFormat(EMITTER_MANIP value); bool SetBoolFormat(EMITTER_MANIP value); bool SetIntBase(EMITTER_MANIP value); diff --git a/include/emittermanip.h b/include/emittermanip.h index 2dd83b5..9284768 100644 --- a/include/emittermanip.h +++ b/include/emittermanip.h @@ -11,6 +11,10 @@ namespace YAML enum EMITTER_MANIP { // general manipulators Auto, + + // output character set + EmitNonAscii, + EscapeNonAscii, // string manipulators // Auto, // duplicate diff --git a/src/emitter.cpp b/src/emitter.cpp index ac305b9..92d76df 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -37,6 +37,11 @@ namespace YAML } // global setters + bool Emitter::SetOutputCharset(EMITTER_MANIP value) + { + return m_pState->SetOutputCharset(value, GLOBAL); + } + bool Emitter::SetStringFormat(EMITTER_MANIP value) { return m_pState->SetStringFormat(value, GLOBAL); @@ -485,13 +490,14 @@ namespace YAML PreAtomicWrite(); EmitSeparationIfNecessary(); + bool escapeNonAscii = m_pState->GetOutputCharset() == EscapeNonAscii; EMITTER_MANIP strFmt = m_pState->GetStringFormat(); FLOW_TYPE flowType = m_pState->GetCurGroupFlowType(); unsigned curIndent = m_pState->GetCurIndent(); switch(strFmt) { case Auto: - Utils::WriteString(m_stream, str, flowType == FT_FLOW); + Utils::WriteString(m_stream, str, flowType == FT_FLOW, escapeNonAscii); break; case SingleQuoted: if(!Utils::WriteSingleQuotedString(m_stream, str)) { @@ -500,11 +506,11 @@ namespace YAML } break; case DoubleQuoted: - Utils::WriteDoubleQuotedString(m_stream, str); + Utils::WriteDoubleQuotedString(m_stream, str, escapeNonAscii); break; case Literal: if(flowType == FT_FLOW) - Utils::WriteString(m_stream, str, flowType == FT_FLOW); + Utils::WriteString(m_stream, str, flowType == FT_FLOW, escapeNonAscii); else Utils::WriteLiteralString(m_stream, str, curIndent + m_pState->GetIndent()); break; diff --git a/src/emitterstate.cpp b/src/emitterstate.cpp index 5a2d8bf..2906679 100644 --- a/src/emitterstate.cpp +++ b/src/emitterstate.cpp @@ -9,6 +9,7 @@ namespace YAML m_stateStack.push(ES_WAITING_FOR_DOC); // set default global manipulators + m_charset.set(EmitNonAscii); m_strFmt.set(Auto); m_boolFmt.set(TrueFalseBool); m_boolLengthFmt.set(LongBool); @@ -43,6 +44,7 @@ namespace YAML // . Only the ones that make sense will be accepted void EmitterState::SetLocalValue(EMITTER_MANIP value) { + SetOutputCharset(value, LOCAL); SetStringFormat(value, LOCAL); SetBoolFormat(value, LOCAL); SetBoolCaseFormat(value, LOCAL); @@ -132,6 +134,18 @@ namespace YAML { m_modifiedSettings.clear(); } + + bool EmitterState::SetOutputCharset(EMITTER_MANIP value, FMT_SCOPE scope) + { + switch(value) { + case EmitNonAscii: + case EscapeNonAscii: + _Set(m_charset, value, scope); + return true; + default: + return false; + } + } bool EmitterState::SetStringFormat(EMITTER_MANIP value, FMT_SCOPE scope) { diff --git a/src/emitterstate.h b/src/emitterstate.h index fbabe81..b5be269 100644 --- a/src/emitterstate.h +++ b/src/emitterstate.h @@ -108,6 +108,9 @@ namespace YAML void ClearModifiedSettings(); // formatters + bool SetOutputCharset(EMITTER_MANIP value, FMT_SCOPE scope); + EMITTER_MANIP GetOutputCharset() const { return m_charset.get(); } + bool SetStringFormat(EMITTER_MANIP value, FMT_SCOPE scope); EMITTER_MANIP GetStringFormat() const { return m_strFmt.get(); } @@ -149,6 +152,7 @@ namespace YAML // other state std::stack m_stateStack; + Setting m_charset; Setting m_strFmt; Setting m_boolFmt; Setting m_boolLengthFmt; diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index f4b7a57..837ae20 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -5,18 +5,129 @@ #include "stringsource.h" #include #include -#include namespace YAML { namespace Utils { namespace { - bool IsPrintable(char ch) { - return (0x20 <= ch && ch <= 0x7E); + enum {REPLACEMENT_CHARACTER = 0xFFFD}; + + bool IsAnchorChar(int ch) { // test for ns-anchor-char + switch (ch) { + case ',': case '[': case ']': case '{': case '}': // c-flow-indicator + case ' ': case '\t': // s-white + case 0xFEFF: // c-byte-order-mark + case 0xA: case 0xD: // b-char + return false; + case 0x85: + return true; + } + + if (ch < 0x20) + return false; + + if (ch < 0x7E) + return true; + + if (ch < 0xA0) + return false; + if (ch >= 0xD800 && ch <= 0xDFFF) + return false; + if ((ch & 0xFFFE) == 0xFFFE) + return false; + if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) + return false; + if (ch > 0x10FFFF) + return false; + + return true; } - bool IsValidPlainScalar(const std::string& str, bool inFlow) { + int Utf8BytesIndicated(char ch) { + int byteVal = static_cast(ch); + switch (byteVal >> 4) { + case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: + return 1; + case 12: case 13: + return 2; + case 14: + return 3; + case 15: + return 4; + default: + return -1; + } + } + + bool IsTrailingByte(char ch) { + return (ch & 0xC0) == 0x80; + } + + bool GetNextCodePointAndAdvance(int& codePoint, std::string::const_iterator& first, std::string::const_iterator last) { + if (first == last) + return false; + + int nBytes = Utf8BytesIndicated(*first); + if (nBytes < 1) { + // Bad lead byte + ++first; + codePoint = REPLACEMENT_CHARACTER; + return true; + } + + if (nBytes == 1) { + codePoint = *first++; + return true; + } + + // Gather bits from trailing bytes + codePoint = static_cast(*first) & ~(0xFF << (7 - nBytes)); + ++first; + --nBytes; + for (; nBytes > 0; ++first, --nBytes) { + if ((first == last) || !IsTrailingByte(*first)) { + codePoint = REPLACEMENT_CHARACTER; + break; + } + codePoint <<= 6; + codePoint |= *first & 0x3F; + } + + // Check for illegal code points + if (codePoint > 0x10FFFF) + codePoint = REPLACEMENT_CHARACTER; + else if (codePoint >= 0xD800 && codePoint <= 0xDFFF) + codePoint = REPLACEMENT_CHARACTER; + else if ((codePoint & 0xFFFE) == 0xFFFE) + codePoint = REPLACEMENT_CHARACTER; + else if (codePoint >= 0xFDD0 && codePoint <= 0xFDEF) + codePoint = REPLACEMENT_CHARACTER; + return true; + } + + void WriteCodePoint(ostream& out, int codePoint) { + if (codePoint < 0 || codePoint > 0x10FFFF) { + codePoint = REPLACEMENT_CHARACTER; + } + if (codePoint < 0x7F) { + out << static_cast(codePoint); + } else if (codePoint < 0x7FF) { + out << static_cast(0xC0 | (codePoint >> 6)) + << static_cast(0x80 | (codePoint & 0x3F)); + } else if (codePoint < 0xFFFF) { + out << static_cast(0xE0 | (codePoint >> 12)) + << static_cast(0x80 | ((codePoint >> 6) & 0x3F)) + << static_cast(0x80 | (codePoint & 0x3F)); + } else { + out << static_cast(0xF0 | (codePoint >> 18)) + << static_cast(0x80 | ((codePoint >> 12) & 0x3F)) + << static_cast(0x80 | ((codePoint >> 6) & 0x3F)) + << static_cast(0x80 | (codePoint & 0x3F)); + } + } + + bool IsValidPlainScalar(const std::string& str, bool inFlow, bool allowOnlyAscii) { // first check the start const RegEx& start = (inFlow ? Exp::PlainScalarInFlow : Exp::PlainScalar); if(!start.Matches(str)) @@ -29,177 +140,109 @@ namespace YAML // then check until something is disallowed const RegEx& disallowed = (inFlow ? Exp::EndScalarInFlow : Exp::EndScalar) || (Exp::BlankOrBreak + Exp::Comment) - || (!Exp::Printable) + || Exp::NotPrintable + || Exp::Utf8_ByteOrderMark || Exp::Break || Exp::Tab; StringCharSource buffer(str.c_str(), str.size()); while(buffer) { if(disallowed.Matches(buffer)) return false; + if(allowOnlyAscii && (0x7F < static_cast(buffer[0]))) + return false; ++buffer; } return true; } - - typedef unsigned char byte; - byte ToByte(char ch) { return static_cast(ch); } - - typedef std::string::const_iterator StrIter; - std::string WriteUnicode(unsigned value) { - std::stringstream str; - // TODO: for the common escaped characters, give their usual symbol - if(value <= 0xFF) - str << "\\x" << std::hex << std::setfill('0') << std::setw(2) << value; - else if(value <= 0xFFFF) - str << "\\u" << std::hex << std::setfill('0') << std::setw(4) << value; - else - str << "\\U" << std::hex << std::setfill('0') << std::setw(8) << value; - return str.str(); - } - - // GetBytesToRead - // . Returns the length of the UTF-8 sequence starting with 'signal' - int GetBytesToRead(byte signal) { - if(signal <= 0x7F) // ASCII - return 1; - else if(signal <= 0xBF) // invalid first characters - return 0; - else if(signal <= 0xDF) // Note: this allows "overlong" UTF8 (0xC0 - 0xC1) to pass unscathed. OK? - return 2; - else if(signal <= 0xEF) - return 3; - else - return 4; - } - - // ReadBytes - // . Reads the next 'bytesToRead', if we can. - // . Returns zero if we fail, otherwise fills the byte buffer with - // the data and returns the number of bytes read. - int ReadBytes(byte bytes[4], StrIter start, StrIter end, int bytesToRead) { - for(int i=0;i 0; --digits, ++i) { + escSeq[i] = hexDigits[(codePoint >> (4 * (digits - 1))) & 0xF]; + } + + escSeq[i] = 0; // terminate with NUL character + out << escSeq; } - - // IsValidUTF8 - // . Assumes bytes[0] is a valid signal byte with the right size passed - bool IsValidUTF8(byte bytes[4], int size) { - for(int i=1;i= 1) - it += (bytesRead - 1); - } + int codePoint; + for(std::string::const_iterator i = str.begin(); + GetNextCodePointAndAdvance(codePoint, i, str.end()); + ) + { + if (codePoint == '\"') + out << "\\\""; + else if (codePoint == '\\') + out << "\\\\"; + else if (codePoint < 0x20 || (codePoint >= 0x80 && codePoint <= 0xA0)) // Control characters and non-breaking space + WriteDoubleQuoteEscapeSequence(out, codePoint); + else if (codePoint == 0xFEFF) // Byte order marks (ZWNS) should be escaped (YAML 1.2, sec. 5.2) + WriteDoubleQuoteEscapeSequence(out, codePoint); + else if (escapeNonAscii && codePoint > 0x7E) + WriteDoubleQuoteEscapeSequence(out, codePoint); + else + WriteCodePoint(out, codePoint); } out << "\""; return true; @@ -209,11 +252,15 @@ namespace YAML { out << "|\n"; out << IndentTo(indent); - for(std::size_t i=0;i(ch); } // Escape diff --git a/src/exp.h b/src/exp.h index e7a96b5..126c2c9 100644 --- a/src/exp.h +++ b/src/exp.h @@ -26,7 +26,12 @@ namespace YAML const RegEx Alpha = RegEx('a', 'z') || RegEx('A', 'Z'); const RegEx AlphaNumeric = Alpha || Digit; const RegEx Hex = Digit || RegEx('A', 'F') || RegEx('a', 'f'); - const RegEx Printable = RegEx(0x20, 0x7E); + // Valid Unicode code points that are not part of c-printable (YAML 1.2, sec. 5.1) + const RegEx NotPrintable = RegEx(0) || + RegEx("\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x7F", REGEX_OR) || + RegEx(0x0E, 0x1F) || + (RegEx('\xC2') + (RegEx('\x80', '\x84') || RegEx('\x86', '\x9F'))); + const RegEx Utf8_ByteOrderMark = RegEx("\xEF\xBB\xBF"); // actual tags diff --git a/yaml-reader/emittertests.cpp b/yaml-reader/emittertests.cpp index c3209b2..f85af8d 100644 --- a/yaml-reader/emittertests.cpp +++ b/yaml-reader/emittertests.cpp @@ -448,12 +448,25 @@ namespace Test desiredOutput = "- ~\n-\n null value: ~\n ~: null key"; } - void Unicode(YAML::Emitter& out, std::string& desiredOutput) + void EscapedUnicode(YAML::Emitter& out, std::string& desiredOutput) { - out << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; + out << YAML::EscapeNonAscii << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; desiredOutput = "\"$ \\xa2 \\u20ac \\U00024b62\""; } + + void Unicode(YAML::Emitter& out, std::string& desiredOutput) + { + out << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; + desiredOutput = "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; + } + + void DoubleQuotedUnicode(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::DoubleQuoted << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; + desiredOutput = "\"\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2\""; + } + //////////////////////////////////////////////////////////////////////////////////////////////////////// // incorrect emitting @@ -616,7 +629,9 @@ namespace Test RunEmitterTest(&Emitter::SimpleGlobalSettings, "simple global settings", passed, total); RunEmitterTest(&Emitter::ComplexGlobalSettings, "complex global settings", passed, total); RunEmitterTest(&Emitter::Null, "null", passed, total); + RunEmitterTest(&Emitter::EscapedUnicode, "escaped unicode", passed, total); RunEmitterTest(&Emitter::Unicode, "unicode", passed, total); + RunEmitterTest(&Emitter::DoubleQuotedUnicode, "double quoted unicode", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total); From 0bf5b133e149ef7ba54c50ba473c66d81cf0dc5a Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 20 Oct 2009 14:43:24 +0000 Subject: [PATCH 182/295] Added a bunch of tests, simplified the testing code --- yaml-reader/spectests.cpp | 466 ++++++++++++++++++++------------------ 1 file changed, 240 insertions(+), 226 deletions(-) diff --git a/yaml-reader/spectests.cpp b/yaml-reader/spectests.cpp index 009c690..c4da43f 100644 --- a/yaml-reader/spectests.cpp +++ b/yaml-reader/spectests.cpp @@ -17,6 +17,12 @@ namespace { } #define YAML_ASSERT(cond) do { if(!(cond)) return " Assert failed: " #cond; } while(false) +#define PARSE(doc, input) \ + std::stringstream stream(input);\ + YAML::Parser parser(stream);\ + YAML::Node doc;\ + parser.GetNextDocument(doc) +#define PARSE_NEXT(doc) parser.GetNextDocument(doc) namespace Test { namespace { @@ -47,11 +53,8 @@ namespace Test { "- Mark McGwire\n" "- Sammy Sosa\n" "- Ken Griffey"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 3); YAML_ASSERT(doc[0] == "Mark McGwire"); YAML_ASSERT(doc[1] == "Sammy Sosa"); @@ -65,11 +68,8 @@ namespace Test { "hr: 65 # Home runs\n" "avg: 0.278 # Batting average\n" "rbi: 147 # Runs Batted In"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); + PARSE(doc, input); YAML_ASSERT(doc.size() == 3); YAML_ASSERT(doc["hr"] == "65"); YAML_ASSERT(doc["avg"] == "0.278"); @@ -88,11 +88,8 @@ namespace Test { "- New York Mets\n" "- Chicago Cubs\n" "- Atlanta Braves"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["american"].size() == 3); YAML_ASSERT(doc["american"][0] == "Boston Red Sox"); @@ -117,11 +114,8 @@ namespace Test { " name: Sammy Sosa\n" " hr: 63\n" " avg: 0.288"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc[0].size() == 3); YAML_ASSERT(doc[0]["name"] == "Mark McGwire"); @@ -141,11 +135,8 @@ namespace Test { "- [name , hr, avg ]\n" "- [Mark McGwire, 65, 0.278]\n" "- [Sammy Sosa , 63, 0.288]"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 3); YAML_ASSERT(doc[0].size() == 3); YAML_ASSERT(doc[0][0] == "name"); @@ -171,11 +162,8 @@ namespace Test { " hr: 63,\n" " avg: 0.288\n" " }"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["Mark McGwire"].size() == 2); YAML_ASSERT(doc["Mark McGwire"]["hr"] == "65"); @@ -200,17 +188,14 @@ namespace Test { "---\n" "- Chicago Cubs\n" "- St Louis Cardinals"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 3); YAML_ASSERT(doc[0] == "Mark McGwire"); YAML_ASSERT(doc[1] == "Sammy Sosa"); YAML_ASSERT(doc[2] == "Ken Griffey"); - - parser.GetNextDocument(doc); + + PARSE_NEXT(doc); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc[0] == "Chicago Cubs"); YAML_ASSERT(doc[1] == "St Louis Cardinals"); @@ -231,17 +216,14 @@ namespace Test { "player: Sammy Sosa\n" "action: grand slam\n" "..."; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 3); YAML_ASSERT(doc["time"] == "20:03:20"); YAML_ASSERT(doc["player"] == "Sammy Sosa"); YAML_ASSERT(doc["action"] == "strike (miss)"); - - parser.GetNextDocument(doc); + + PARSE_NEXT(doc); YAML_ASSERT(doc.size() == 3); YAML_ASSERT(doc["time"] == "20:03:47"); YAML_ASSERT(doc["player"] == "Sammy Sosa"); @@ -261,11 +243,8 @@ namespace Test { " # 1998 rbi ranking\n" " - Sammy Sosa\n" " - Ken Griffey"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["hr"].size() == 2); YAML_ASSERT(doc["hr"][0] == "Mark McGwire"); @@ -288,11 +267,8 @@ namespace Test { "rbi:\n" " - *SS # Subsequent occurrence\n" " - Ken Griffey"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["hr"].size() == 2); YAML_ASSERT(doc["hr"][0] == "Mark McGwire"); @@ -331,11 +307,8 @@ namespace Test { " Atlanta Braves ]\n" ": [ 2001-07-02, 2001-08-12,\n" " 2001-08-14 ]"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); + PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc[Pair("Detroit Tigers", "Chicago cubs")].size() == 1); YAML_ASSERT(doc[Pair("Detroit Tigers", "Chicago cubs")][0] == "2001-07-23"); @@ -358,11 +331,8 @@ namespace Test { " quantity: 4\n" "- item : Big Shoes\n" " quantity: 1"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 3); YAML_ASSERT(doc[0].size() == 2); YAML_ASSERT(doc[0]["item"] == "Super Hoop"); @@ -384,11 +354,8 @@ namespace Test { "--- |\n" " \\//||\\/||\n" " // || ||__"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc == "\\//||\\/||\n" "// || ||__"); @@ -403,11 +370,8 @@ namespace Test { " Mark McGwire's\n" " year was crippled\n" " by a knee injury."; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc == "Mark McGwire's year was crippled by a knee injury."); return true; } @@ -424,11 +388,8 @@ namespace Test { " 0.288 Batting Average\n" " \n" " What a year!"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc == "Sammy Sosa completed another fine season with great stats.\n\n" " 63 Home Runs\n" @@ -448,11 +409,8 @@ namespace Test { "stats: |\n" " 65 Home Runs\n" " 0.278 Batting Average\n"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 3); YAML_ASSERT(doc["name"] == "Mark McGwire"); YAML_ASSERT(doc["accomplishment"] == "Mark set a major league home run record in 1998.\n"); @@ -471,11 +429,8 @@ namespace Test { "single: '\"Howdy!\" he cried.'\n" "quoted: ' # Not a ''comment''.'\n" "tie-fighter: '|\\-*-/|'"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 6); YAML_ASSERT(doc["unicode"] == "Sosa did fine.\xe2\x98\xba"); YAML_ASSERT(doc["control"] == "\b1998\t1999\t2000\n"); @@ -496,11 +451,8 @@ namespace Test { "\n" "quoted: \"So does this\n" " quoted scalar.\\n\""; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["plain"] == "This unquoted scalar spans many lines."); YAML_ASSERT(doc["quoted"] == "So does this quoted scalar.\n"); @@ -542,11 +494,8 @@ namespace Test { " Late afternoon is best.\n" " Backup contact is Nancy\n" " Billsmer @ 338-4338."; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 8); YAML_ASSERT(doc["invoice"] == 34843); YAML_ASSERT(doc["date"] == "2001-01-23"); @@ -613,23 +562,20 @@ namespace Test { " line: 58\n" " code: |-\n" " foo = bar"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 3); YAML_ASSERT(doc["Time"] == "2001-11-23 15:01:42 -5"); YAML_ASSERT(doc["User"] == "ed"); YAML_ASSERT(doc["Warning"] == "This is an error message for the log file"); - - parser.GetNextDocument(doc); + + PARSE_NEXT(doc); YAML_ASSERT(doc.size() == 3); YAML_ASSERT(doc["Time"] == "2001-11-23 15:02:31 -5"); YAML_ASSERT(doc["User"] == "ed"); YAML_ASSERT(doc["Warning"] == "A slightly different error message."); - - parser.GetNextDocument(doc); + + PARSE_NEXT(doc); YAML_ASSERT(doc.size() == 4); YAML_ASSERT(doc["Date"] == "2001-11-23 15:03:17 -5"); YAML_ASSERT(doc["User"] == "ed"); @@ -659,11 +605,8 @@ namespace Test { " ? sky\n" " : blue\n" " sea : green"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["sequence"].size() == 2); YAML_ASSERT(doc["sequence"][0] == "one"); @@ -680,11 +623,8 @@ namespace Test { std::string input = "sequence: [ one, two, ]\n" "mapping: { sky: blue, sea: green }"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["sequence"].size() == 2); YAML_ASSERT(doc["sequence"][0] == "one"); @@ -703,11 +643,8 @@ namespace Test { std::string input = "anchored: !local &anchor value\n" "alias: *anchor"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["anchored"] == "value"); // TODO: assert tag YAML_ASSERT(doc["alias"] == "value"); @@ -724,11 +661,8 @@ namespace Test { "folded: >\n" " some\n" " text\n"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["literal"] == "some\ntext\n"); YAML_ASSERT(doc["folded"] == "some text\n"); @@ -741,11 +675,8 @@ namespace Test { std::string input = "single: 'text'\n" "double: \"text\""; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["single"] == "text"); YAML_ASSERT(doc["double"] == "text"); @@ -762,11 +693,8 @@ namespace Test { "|\n" " Line break (no glyph)\n" " Line break (glyphed)\n"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc == "Line break (no glyph)\nLine break (glyphed)\n"); return true; } @@ -781,11 +709,8 @@ namespace Test { " void main() {\n" " \tprintf(\"Hello, world!\\n\");\n" " }"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["quoted"] == "Quoted\t"); YAML_ASSERT(doc["block"] == @@ -804,11 +729,8 @@ namespace Test { "\\n \\r \\t \\v \\0 \\\n" "\\ \\_ \\N \\L \\P \\\n" "\\x41 \\u0041 \\U00000041\""; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc == "Fun with \x5C \x22 \x07 \x08 \x1B \x0C \x0A \x0D \x09 \x0B " + std::string("\x00", 1) + " \x20 \xA0 \x85 \xe2\x80\xa8 \xe2\x80\xa9 A A A"); return true; } @@ -850,11 +772,8 @@ namespace Test { " Also by two, # are neither\n" " \tStill by two # content nor\n" " ] # indentation."; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 1); YAML_ASSERT(doc["Not indented"].size() == 2); YAML_ASSERT(doc["Not indented"]["By one space"] == "By four\n spaces\n"); @@ -873,11 +792,8 @@ namespace Test { ": -\tb\n" " - -\tc\n" " - d"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 1); YAML_ASSERT(doc["a"].size() == 2); YAML_ASSERT(doc["a"][0] == "b"); @@ -894,11 +810,8 @@ namespace Test { "- foo:\t bar\n" "- - baz\n" " -\tbaz"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc[0].size() == 1); YAML_ASSERT(doc[0]["foo"] == "bar"); @@ -919,11 +832,8 @@ namespace Test { "block: |\n" " text\n" " \tlines\n"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 3); YAML_ASSERT(doc["plain"] == "text lines"); YAML_ASSERT(doc["quoted"] == "text lines"); @@ -942,11 +852,8 @@ namespace Test { "Chomping: |\n" " Clipped empty lines\n" " "; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["Folding"] == "Empty line\nas a line feed"); YAML_ASSERT(doc["Chomping"] == "Clipped empty lines\n"); @@ -964,11 +871,8 @@ namespace Test { "\n" " as\n" " space"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc == "trimmed\n\n\nas space"); return true; } @@ -983,11 +887,8 @@ namespace Test { " \t bar\n" "\n" " baz\n"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc == "foo \n\n\t bar\n\nbaz\n"); return true; } @@ -1003,11 +904,8 @@ namespace Test { "\n" " baz\n" "\""; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc == " foo\nbar\nbaz "); return true; } @@ -1018,11 +916,8 @@ namespace Test { std::string input = "key: # Comment\n" " value"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 1); YAML_ASSERT(doc["key"] == "value"); return true; @@ -1050,11 +945,8 @@ namespace Test { " # lines\n" " value\n" "\n"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 1); YAML_ASSERT(doc["key"] == "value"); return true; @@ -1089,11 +981,8 @@ namespace Test { " 65\n" " avg: # Average\n" " 0.278"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); StringMap key; key._["first"] = "Sammy"; key._["last"] = "Sosa"; @@ -1113,11 +1002,8 @@ namespace Test { std::string input = "First occurrence: &anchor Value\n" "Second occurrence: *anchor"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["First occurrence"] == "Value"); YAML_ASSERT(doc["Second occurrence"] == "Value"); @@ -1132,11 +1018,8 @@ namespace Test { "Second occurrence: *anchor\n" "Override anchor: &anchor Bar\n" "Reuse anchor: *anchor"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 4); YAML_ASSERT(doc["First occurrence"] == "Foo"); YAML_ASSERT(doc["Second occurrence"] == "Foo"); @@ -1153,11 +1036,8 @@ namespace Test { " foo : !!str,\n" " !!str : bar,\n" "}"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["foo"] == ""); // TODO: check tag YAML_ASSERT(doc[""] == "bar"); @@ -1172,11 +1052,8 @@ namespace Test { " ? foo :,\n" " : bar,\n" "}\n"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(IsNull(doc["foo"])); YAML_ASSERT(doc[YAML::Null] == "bar"); @@ -1190,17 +1067,146 @@ namespace Test { "\"implicit block key\" : [\n" " \"implicit flow key\" : value,\n" " ]"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - + + PARSE(doc, input); YAML_ASSERT(doc.size() == 1); YAML_ASSERT(doc["implicit block key"].size() == 1); YAML_ASSERT(doc["implicit block key"][0].size() == 1); YAML_ASSERT(doc["implicit block key"][0]["implicit flow key"] == "value"); return true; } + + // 7.5 + TEST DoubleQuotedLineBreaks() + { + std::string input = + "\"folded \n" + "to a space,\t\n" + " \n" + "to a line feed, or \t\\\n" + " \\ \tnon-content\""; + + PARSE(doc, input); + YAML_ASSERT(doc == "folded to a space,\nto a line feed, or \t \tnon-content"); + return true; + } + + // 7.6 + TEST DoubleQuotedLines() + { + std::string input = + "\" 1st non-empty\n" + "\n" + " 2nd non-empty \n" + "\t3rd non-empty \""; + + PARSE(doc, input); + YAML_ASSERT(doc == " 1st non-empty\n2nd non-empty 3rd non-empty "); + return true; + } + + // 7.7 + TEST SingleQuotedCharacters() + { + std::string input = " 'here''s to \"quotes\"'"; + + PARSE(doc, input); + YAML_ASSERT(doc == "here's to \"quotes\""); + return true; + } + + // 7.8 + TEST SingleQuotedImplicitKeys() + { + std::string input = + "'implicit block key' : [\n" + " 'implicit flow key' : value,\n" + " ]"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc["implicit block key"].size() == 1); + YAML_ASSERT(doc["implicit block key"][0].size() == 1); + YAML_ASSERT(doc["implicit block key"][0]["implicit flow key"] == "value"); + return true; + } + + // 7.9 + TEST SingleQuotedLines() + { + std::string input = + "' 1st non-empty\n" + "\n" + " 2nd non-empty \n" + "\t3rd non-empty '"; + + PARSE(doc, input); + YAML_ASSERT(doc == " 1st non-empty\n2nd non-empty 3rd non-empty "); + return true; + } + + // 7.10 + TEST PlainCharacters() + { + std::string input = + "# Outside flow collection:\n" + "- ::vector\n" + "- \": - ()\"\n" + "- Up, up, and away!\n" + "- -123\n" + "- http://example.com/foo#bar\n" + "# Inside flow collection:\n" + "- [ ::vector,\n" + " \": - ()\",\n" + " \"Up, up, and away!\",\n" + " -123,\n" + " http://example.com/foo#bar ]"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 6); + YAML_ASSERT(doc[0] == "::vector"); + YAML_ASSERT(doc[1] == ": - ()"); + YAML_ASSERT(doc[2] == "Up, up, and away!"); + YAML_ASSERT(doc[3] == -123); + YAML_ASSERT(doc[4] == "http://example.com/foo#bar"); + YAML_ASSERT(doc[5].size() == 5); + YAML_ASSERT(doc[5][0] == "::vector"); + YAML_ASSERT(doc[5][1] == ": - ()"); + YAML_ASSERT(doc[5][2] == "Up, up, and away!"); + YAML_ASSERT(doc[5][3] == -123); + YAML_ASSERT(doc[5][4] == "http://example.com/foo#bar"); + return true; + } + + // 7.11 + TEST PlainImplicitKeys() + { + std::string input = + "implicit block key : [\n" + " implicit flow key : value,\n" + " ]"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc["implicit block key"].size() == 1); + YAML_ASSERT(doc["implicit block key"][0].size() == 1); + YAML_ASSERT(doc["implicit block key"][0]["implicit flow key"] == "value"); + return true; + } + + // 7.12 + TEST PlainLines() + { + std::string input = + "1st non-empty\n" + "\n" + " 2nd non-empty \n" + "\t3rd non-empty"; + + PARSE(doc, input); + YAML_ASSERT(doc == "1st non-empty\n2nd non-empty 3rd non-empty"); + return true; + } } bool RunSpecTests() @@ -1257,6 +1263,14 @@ namespace Test { RunSpecTest(&Spec::EmptyNodes, "7.2", "Empty Nodes", passed, total); RunSpecTest(&Spec::CompletelyEmptyNodes, "7.3", "Completely Empty Nodes", passed, total); RunSpecTest(&Spec::DoubleQuotedImplicitKeys, "7.4", "Double Quoted Implicit Keys", passed, total); + RunSpecTest(&Spec::DoubleQuotedLineBreaks, "7.5", "Double Quoted Line Breaks", passed, total); + RunSpecTest(&Spec::DoubleQuotedLines, "7.6", "Double Quoted Lines", passed, total); + RunSpecTest(&Spec::SingleQuotedCharacters, "7.7", "Single Quoted Characters", passed, total); + RunSpecTest(&Spec::SingleQuotedImplicitKeys, "7.8", "Single Quoted Implicit Keys", passed, total); + RunSpecTest(&Spec::SingleQuotedLines, "7.9", "Single Quoted Lines", passed, total); + RunSpecTest(&Spec::PlainCharacters, "7.10", "Plain Characters", passed, total); + RunSpecTest(&Spec::PlainImplicitKeys, "7.11", "Plain Implicit Keys", passed, total); + RunSpecTest(&Spec::PlainLines, "7.12", "Plain Lines", passed, total); std::cout << "Spec tests: " << passed << "/" << total << " passed\n"; return passed == total; From 68df40c1dc4ee0554923f443f5870cf21ba33e20 Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 20 Oct 2009 14:47:16 +0000 Subject: [PATCH 183/295] Fixed bug in plain scalar folding --- src/scantoken.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scantoken.cpp b/src/scantoken.cpp index df8e11e..80999bd 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -287,7 +287,7 @@ namespace YAML params.end = (InFlowContext() ? Exp::EndScalarInFlow : Exp::EndScalar) || (Exp::BlankOrBreak + Exp::Comment); params.eatEnd = false; params.indent = (InFlowContext() ? 0 : GetTopIndent() + 1); - params.fold = FOLD_BLOCK; + params.fold = FOLD_FLOW; params.eatLeadingWhitespace = true; params.trimTrailingSpaces = true; params.chomp = STRIP; From 2022379cf41760bc4b2be49b43be47c34f67a974 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 22 Oct 2009 14:17:12 +0000 Subject: [PATCH 184/295] Switch to flow sequence when emitting an empty sequence --- src/emitter.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/emitter.cpp b/src/emitter.cpp index 92d76df..9a48318 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -349,12 +349,18 @@ namespace YAML EMITTER_STATE curState = m_pState->GetCurState(); FLOW_TYPE flowType = m_pState->GetCurGroupFlowType(); - if(flowType == FT_BLOCK) - assert(curState == ES_DONE_WITH_BLOCK_SEQ_ENTRY); - else if(flowType == FT_FLOW) { - m_stream << "]"; + if(flowType == FT_BLOCK) { + // Note: block sequences are *not* allowed to be empty, but we convert it + // to a flow sequence if it is + assert(curState == ES_DONE_WITH_BLOCK_SEQ_ENTRY || curState == ES_WAITING_FOR_BLOCK_SEQ_ENTRY); + if(curState == ES_WAITING_FOR_BLOCK_SEQ_ENTRY) { + unsigned curIndent = m_pState->GetCurIndent(); + m_stream << IndentTo(curIndent) << "[]"; + } + } else if(flowType == FT_FLOW) { // Note: flow sequences are allowed to be empty assert(curState == ES_DONE_WITH_FLOW_SEQ_ENTRY || curState == ES_WAITING_FOR_FLOW_SEQ_ENTRY); + m_stream << "]"; } else assert(false); @@ -685,3 +691,4 @@ namespace YAML return *this; } } + From 2b2fca758c5ba1c6833c60ec1982395504550c80 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 22 Oct 2009 14:21:12 +0000 Subject: [PATCH 185/295] Switch to flow map when emitting an empty block map --- src/emitter.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/emitter.cpp b/src/emitter.cpp index 9a48318..5eb4bc4 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -410,12 +410,18 @@ namespace YAML EMITTER_STATE curState = m_pState->GetCurState(); FLOW_TYPE flowType = m_pState->GetCurGroupFlowType(); - if(flowType == FT_BLOCK) - assert(curState == ES_DONE_WITH_BLOCK_MAP_VALUE); - else if(flowType == FT_FLOW) { - m_stream << "}"; + if(flowType == FT_BLOCK) { + // Note: block sequences are *not* allowed to be empty, but we convert it + // to a flow sequence if it is + assert(curState == ES_DONE_WITH_BLOCK_MAP_VALUE || curState == ES_WAITING_FOR_BLOCK_MAP_ENTRY); + if(curState == ES_WAITING_FOR_BLOCK_MAP_ENTRY) { + unsigned curIndent = m_pState->GetCurIndent(); + m_stream << IndentTo(curIndent) << "{}"; + } + } else if(flowType == FT_FLOW) { // Note: flow maps are allowed to be empty assert(curState == ES_DONE_WITH_FLOW_MAP_VALUE || curState == ES_WAITING_FOR_FLOW_MAP_ENTRY); + m_stream << "}"; } else assert(false); From 9ee348d62e4781140ce336d8f7fc167f9b86746d Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 22 Oct 2009 21:51:32 +0000 Subject: [PATCH 186/295] Small refactoring --- src/exp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/exp.cpp b/src/exp.cpp index 969a80b..22080c6 100644 --- a/src/exp.cpp +++ b/src/exp.cpp @@ -30,7 +30,7 @@ namespace YAML std::string Str(unsigned ch) { - return std::string("") + static_cast(ch); + return std::string(1, static_cast(ch)); } // Escape From 770466d5d414a5141a6611696293836b10a81ded Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 22 Oct 2009 21:55:44 +0000 Subject: [PATCH 187/295] Tagged version 0.2.3 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6116c27..71b601e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ endif(CMAKE_COMPILER_IS_GNUCC) set(YAML_CPP_VERSION_MAJOR "0") set(YAML_CPP_VERSION_MINOR "2") -set(YAML_CPP_VERSION_PATCH "2") +set(YAML_CPP_VERSION_PATCH "3") set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}") enable_testing() From 52e3e0a4aa446cfff3ddafd3ad7a663757733d16 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sun, 25 Oct 2009 18:01:48 +0000 Subject: [PATCH 188/295] Updated the CMake globbing so it only compiles sources starting with a lowercase letter (apparently Mac OS auto-generates files looking like ._whatever and it was trying to compile those too) --- CMakeLists.txt | 6 +++--- yaml-reader/CMakeLists.txt | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 71b601e..440aa27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,9 +38,9 @@ set(_INSTALL_DESTINATIONS ARCHIVE DESTINATION lib${LIB_SUFFIX} ) # -file(GLOB public_headers include/*.h) -file(GLOB private_headers src/*.h) -file(GLOB sources src/*.cpp) +file(GLOB public_headers include/[a-z]*.h) +file(GLOB private_headers src/[a-z]*.h) +file(GLOB sources src/[a-z]*.cpp) include_directories(${YAML_CPP_SOURCE_DIR}/include) add_library(yaml-cpp diff --git a/yaml-reader/CMakeLists.txt b/yaml-reader/CMakeLists.txt index f2c3ce2..2b58180 100644 --- a/yaml-reader/CMakeLists.txt +++ b/yaml-reader/CMakeLists.txt @@ -1,5 +1,5 @@ -file(GLOB yaml-reader_headers *.h) -file(GLOB yaml-reader_sources *.cpp) +file(GLOB yaml-reader_headers [a-z]*.h) +file(GLOB yaml-reader_sources [a-z]*.cpp) add_executable(yaml-reader ${yaml-reader_sources} From 47628bf25e174ea1eff89a8d03b4a259084c6f8e Mon Sep 17 00:00:00 2001 From: jbeder Date: Sun, 25 Oct 2009 20:27:31 +0000 Subject: [PATCH 189/295] Tagged version 0.2.4 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 440aa27..9e061e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ endif(CMAKE_COMPILER_IS_GNUCC) set(YAML_CPP_VERSION_MAJOR "0") set(YAML_CPP_VERSION_MINOR "2") -set(YAML_CPP_VERSION_PATCH "3") +set(YAML_CPP_VERSION_PATCH "4") set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}") enable_testing() From 7d5988401e0190a7701c91ca00fd40081402dd47 Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 27 Oct 2009 14:38:53 +0000 Subject: [PATCH 190/295] Renamed yaml-reader test --- CMakeLists.txt | 2 +- test/CMakeLists.txt | 10 ++++++++++ {yaml-reader => test}/emittertests.cpp | 0 {yaml-reader => test}/emittertests.h | 0 {yaml-reader => test}/main.cpp | 0 {yaml-reader => test}/parsertests.cpp | 0 {yaml-reader => test}/parsertests.h | 0 {yaml-reader => test}/spectests.cpp | 0 {yaml-reader => test}/spectests.h | 0 {yaml-reader => test}/tests.cpp | 0 {yaml-reader => test}/tests.h | 0 yaml-reader/CMakeLists.txt | 10 ---------- yaml-reader/tests/aliased.yaml | 4 ---- 13 files changed, 11 insertions(+), 15 deletions(-) create mode 100644 test/CMakeLists.txt rename {yaml-reader => test}/emittertests.cpp (100%) rename {yaml-reader => test}/emittertests.h (100%) rename {yaml-reader => test}/main.cpp (100%) rename {yaml-reader => test}/parsertests.cpp (100%) rename {yaml-reader => test}/parsertests.h (100%) rename {yaml-reader => test}/spectests.cpp (100%) rename {yaml-reader => test}/spectests.h (100%) rename {yaml-reader => test}/tests.cpp (100%) rename {yaml-reader => test}/tests.h (100%) delete mode 100644 yaml-reader/CMakeLists.txt delete mode 100644 yaml-reader/tests/aliased.yaml diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e061e0..8c42e23 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,6 @@ if(UNIX) endif(UNIX) if(YAML_CPP_BUILD_TOOLS) - add_subdirectory (yaml-reader) + add_subdirectory (test) add_subdirectory (util) endif(YAML_CPP_BUILD_TOOLS) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..9e318f1 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,10 @@ +file(GLOB test_headers [a-z]*.h) +file(GLOB test_sources [a-z]*.cpp) + +add_executable(run-tests + ${test_sources} + ${test_headers} +) +target_link_libraries(run-tests yaml-cpp) + +add_test(yaml-reader-test run-tests) diff --git a/yaml-reader/emittertests.cpp b/test/emittertests.cpp similarity index 100% rename from yaml-reader/emittertests.cpp rename to test/emittertests.cpp diff --git a/yaml-reader/emittertests.h b/test/emittertests.h similarity index 100% rename from yaml-reader/emittertests.h rename to test/emittertests.h diff --git a/yaml-reader/main.cpp b/test/main.cpp similarity index 100% rename from yaml-reader/main.cpp rename to test/main.cpp diff --git a/yaml-reader/parsertests.cpp b/test/parsertests.cpp similarity index 100% rename from yaml-reader/parsertests.cpp rename to test/parsertests.cpp diff --git a/yaml-reader/parsertests.h b/test/parsertests.h similarity index 100% rename from yaml-reader/parsertests.h rename to test/parsertests.h diff --git a/yaml-reader/spectests.cpp b/test/spectests.cpp similarity index 100% rename from yaml-reader/spectests.cpp rename to test/spectests.cpp diff --git a/yaml-reader/spectests.h b/test/spectests.h similarity index 100% rename from yaml-reader/spectests.h rename to test/spectests.h diff --git a/yaml-reader/tests.cpp b/test/tests.cpp similarity index 100% rename from yaml-reader/tests.cpp rename to test/tests.cpp diff --git a/yaml-reader/tests.h b/test/tests.h similarity index 100% rename from yaml-reader/tests.h rename to test/tests.h diff --git a/yaml-reader/CMakeLists.txt b/yaml-reader/CMakeLists.txt deleted file mode 100644 index 2b58180..0000000 --- a/yaml-reader/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -file(GLOB yaml-reader_headers [a-z]*.h) -file(GLOB yaml-reader_sources [a-z]*.cpp) - -add_executable(yaml-reader - ${yaml-reader_sources} - ${yaml-reader_headers} -) -target_link_libraries(yaml-reader yaml-cpp) - -add_test(yaml-reader-test yaml-reader) diff --git a/yaml-reader/tests/aliased.yaml b/yaml-reader/tests/aliased.yaml deleted file mode 100644 index ca79a64..0000000 --- a/yaml-reader/tests/aliased.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- &list -- This document contains a recursive list. -- *list -... From 50b026a3a917b0c53990425fcfc802ab288c9738 Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 27 Oct 2009 14:39:48 +0000 Subject: [PATCH 191/295] Renamed yaml-reader test (try 2) --- test/tests/aliased.yaml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 test/tests/aliased.yaml diff --git a/test/tests/aliased.yaml b/test/tests/aliased.yaml new file mode 100644 index 0000000..ca79a64 --- /dev/null +++ b/test/tests/aliased.yaml @@ -0,0 +1,4 @@ +--- &list +- This document contains a recursive list. +- *list +... From d3b00fa6c54100f0a6ca51fb4c40256223370870 Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 27 Oct 2009 14:45:14 +0000 Subject: [PATCH 192/295] Reverted yaml-reader name change --- CMakeLists.txt | 2 +- yaml-reader/CMakeLists.txt | 10 + yaml-reader/emittertests.cpp | 650 ++++++++++++++++ yaml-reader/emittertests.h | 11 + yaml-reader/main.cpp | 11 + yaml-reader/parsertests.cpp | 888 ++++++++++++++++++++++ yaml-reader/parsertests.h | 11 + yaml-reader/spectests.cpp | 1280 ++++++++++++++++++++++++++++++++ yaml-reader/spectests.h | 11 + yaml-reader/tests.cpp | 29 + yaml-reader/tests.h | 51 ++ yaml-reader/tests/aliased.yaml | 4 + 12 files changed, 2957 insertions(+), 1 deletion(-) create mode 100644 yaml-reader/CMakeLists.txt create mode 100644 yaml-reader/emittertests.cpp create mode 100644 yaml-reader/emittertests.h create mode 100644 yaml-reader/main.cpp create mode 100644 yaml-reader/parsertests.cpp create mode 100644 yaml-reader/parsertests.h create mode 100644 yaml-reader/spectests.cpp create mode 100644 yaml-reader/spectests.h create mode 100644 yaml-reader/tests.cpp create mode 100644 yaml-reader/tests.h create mode 100644 yaml-reader/tests/aliased.yaml diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c42e23..9e061e0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,6 @@ if(UNIX) endif(UNIX) if(YAML_CPP_BUILD_TOOLS) - add_subdirectory (test) + add_subdirectory (yaml-reader) add_subdirectory (util) endif(YAML_CPP_BUILD_TOOLS) diff --git a/yaml-reader/CMakeLists.txt b/yaml-reader/CMakeLists.txt new file mode 100644 index 0000000..2b58180 --- /dev/null +++ b/yaml-reader/CMakeLists.txt @@ -0,0 +1,10 @@ +file(GLOB yaml-reader_headers [a-z]*.h) +file(GLOB yaml-reader_sources [a-z]*.cpp) + +add_executable(yaml-reader + ${yaml-reader_sources} + ${yaml-reader_headers} +) +target_link_libraries(yaml-reader yaml-cpp) + +add_test(yaml-reader-test yaml-reader) diff --git a/yaml-reader/emittertests.cpp b/yaml-reader/emittertests.cpp new file mode 100644 index 0000000..f85af8d --- /dev/null +++ b/yaml-reader/emittertests.cpp @@ -0,0 +1,650 @@ +#include "tests.h" +#include "yaml.h" + +namespace Test +{ + namespace Emitter { + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // correct emitting + + void SimpleScalar(YAML::Emitter& out, std::string& desiredOutput) { + out << "Hello, World!"; + desiredOutput = "Hello, World!"; + } + + void SimpleSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginSeq; + out << "eggs"; + out << "bread"; + out << "milk"; + out << YAML::EndSeq; + + desiredOutput = "- eggs\n- bread\n- milk"; + } + + void SimpleFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::Flow; + out << YAML::BeginSeq; + out << "Larry"; + out << "Curly"; + out << "Moe"; + out << YAML::EndSeq; + + desiredOutput = "[Larry, Curly, Moe]"; + } + + void EmptyFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::Flow; + out << YAML::BeginSeq; + out << YAML::EndSeq; + + desiredOutput = "[]"; + } + + void NestedBlockSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginSeq; + out << "item 1"; + out << YAML::BeginSeq << "subitem 1" << "subitem 2" << YAML::EndSeq; + out << YAML::EndSeq; + + desiredOutput = "- item 1\n-\n - subitem 1\n - subitem 2"; + } + + void NestedFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginSeq; + out << "one"; + out << YAML::Flow << YAML::BeginSeq << "two" << "three" << YAML::EndSeq; + out << YAML::EndSeq; + + desiredOutput = "- one\n- [two, three]"; + } + + void SimpleMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Ryan Braun"; + out << YAML::Key << "position"; + out << YAML::Value << "3B"; + out << YAML::EndMap; + + desiredOutput = "name: Ryan Braun\nposition: 3B"; + } + + void SimpleFlowMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::Flow; + out << YAML::BeginMap; + out << YAML::Key << "shape"; + out << YAML::Value << "square"; + out << YAML::Key << "color"; + out << YAML::Value << "blue"; + out << YAML::EndMap; + + desiredOutput = "{shape: square, color: blue}"; + } + + void MapAndList(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Barack Obama"; + out << YAML::Key << "children"; + out << YAML::Value << YAML::BeginSeq << "Sasha" << "Malia" << YAML::EndSeq; + out << YAML::EndMap; + + desiredOutput = "name: Barack Obama\nchildren:\n - Sasha\n - Malia"; + } + + void ListAndMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginSeq; + out << "item 1"; + out << YAML::BeginMap; + out << YAML::Key << "pens" << YAML::Value << 8; + out << YAML::Key << "pencils" << YAML::Value << 14; + out << YAML::EndMap; + out << "item 2"; + out << YAML::EndSeq; + + desiredOutput = "- item 1\n-\n pens: 8\n pencils: 14\n- item 2"; + } + + void NestedBlockMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Fred"; + out << YAML::Key << "grades"; + out << YAML::Value; + out << YAML::BeginMap; + out << YAML::Key << "algebra" << YAML::Value << "A"; + out << YAML::Key << "physics" << YAML::Value << "C+"; + out << YAML::Key << "literature" << YAML::Value << "B"; + out << YAML::EndMap; + out << YAML::EndMap; + + desiredOutput = "name: Fred\ngrades:\n algebra: A\n physics: C+\n literature: B"; + } + + void NestedFlowMap(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::Flow; + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Fred"; + out << YAML::Key << "grades"; + out << YAML::Value; + out << YAML::BeginMap; + out << YAML::Key << "algebra" << YAML::Value << "A"; + out << YAML::Key << "physics" << YAML::Value << "C+"; + out << YAML::Key << "literature" << YAML::Value << "B"; + out << YAML::EndMap; + out << YAML::EndMap; + + desiredOutput = "{name: Fred, grades: {algebra: A, physics: C+, literature: B}}"; + } + + void MapListMix(YAML::Emitter& out, std::string& desiredOutput) { + out << YAML::BeginMap; + out << YAML::Key << "name"; + out << YAML::Value << "Bob"; + out << YAML::Key << "position"; + out << YAML::Value; + out << YAML::Flow << YAML::BeginSeq << 2 << 4 << YAML::EndSeq; + out << YAML::Key << "invincible" << YAML::Value << YAML::OnOffBool << false; + out << YAML::EndMap; + + desiredOutput = "name: Bob\nposition: [2, 4]\ninvincible: off"; + } + + void SimpleLongKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::LongKey; + out << YAML::BeginMap; + out << YAML::Key << "height"; + out << YAML::Value << "5'9\""; + out << YAML::Key << "weight"; + out << YAML::Value << 145; + out << YAML::EndMap; + + desiredOutput = "? height\n: 5'9\"\n? weight\n: 145"; + } + + void SingleLongKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << "age"; + out << YAML::Value << "24"; + out << YAML::LongKey << YAML::Key << "height"; + out << YAML::Value << "5'9\""; + out << YAML::Key << "weight"; + out << YAML::Value << 145; + out << YAML::EndMap; + + desiredOutput = "age: 24\n? height\n: 5'9\"\nweight: 145"; + } + + void ComplexLongKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::LongKey; + out << YAML::BeginMap; + out << YAML::Key << YAML::BeginSeq << 1 << 3 << YAML::EndSeq; + out << YAML::Value << "monster"; + out << YAML::Key << YAML::Flow << YAML::BeginSeq << 2 << 0 << YAML::EndSeq; + out << YAML::Value << "demon"; + out << YAML::EndMap; + + desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon"; + } + + void AutoLongKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << YAML::BeginSeq << 1 << 3 << YAML::EndSeq; + out << YAML::Value << "monster"; + out << YAML::Key << YAML::Flow << YAML::BeginSeq << 2 << 0 << YAML::EndSeq; + out << YAML::Value << "demon"; + out << YAML::Key << "the origin"; + out << YAML::Value << "angel"; + out << YAML::EndMap; + + desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon\nthe origin: angel"; + } + + void ScalarFormat(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << "simple scalar"; + out << YAML::SingleQuoted << "explicit single-quoted scalar"; + out << YAML::DoubleQuoted << "explicit double-quoted scalar"; + out << "auto-detected\ndouble-quoted scalar"; + out << "a non-\"auto-detected\" double-quoted scalar"; + out << YAML::Literal << "literal scalar\nthat may span\nmany, many\nlines and have \"whatever\" crazy\tsymbols that we like"; + out << YAML::EndSeq; + + desiredOutput = "- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\x0adouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like"; + } + + void AutoLongKeyScalar(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << YAML::Literal << "multi-line\nscalar"; + out << YAML::Value << "and its value"; + out << YAML::EndMap; + + desiredOutput = "? |\n multi-line\n scalar\n: and its value"; + } + + void LongKeyFlowMap(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Flow; + out << YAML::BeginMap; + out << YAML::Key << "simple key"; + out << YAML::Value << "and value"; + out << YAML::LongKey << YAML::Key << "long key"; + out << YAML::Value << "and its value"; + out << YAML::EndMap; + + desiredOutput = "{simple key: and value, ? long key: and its value}"; + } + + void BlockMapAsKey(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key; + out << YAML::BeginMap; + out << YAML::Key << "key" << YAML::Value << "value"; + out << YAML::Key << "next key" << YAML::Value << "next value"; + out << YAML::EndMap; + out << YAML::Value; + out << "total value"; + out << YAML::EndMap; + + desiredOutput = "?\n key: value\n next key: next value\n: total value"; + } + + void AliasAndAnchor(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << YAML::Anchor("fred"); + out << YAML::BeginMap; + out << YAML::Key << "name" << YAML::Value << "Fred"; + out << YAML::Key << "age" << YAML::Value << 42; + out << YAML::EndMap; + out << YAML::Alias("fred"); + out << YAML::EndSeq; + + desiredOutput = "- &fred\n name: Fred\n age: 42\n- *fred"; + } + + void AliasAndAnchorWithNull(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << YAML::Anchor("fred") << YAML::Null; + out << YAML::Alias("fred"); + out << YAML::EndSeq; + + desiredOutput = "- &fred ~\n- *fred"; + } + + void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << "receipt"; + out << YAML::Value << "Oz-Ware Purchase Invoice"; + out << YAML::Key << "date"; + out << YAML::Value << "2007-08-06"; + out << YAML::Key << "customer"; + out << YAML::Value; + out << YAML::BeginMap; + out << YAML::Key << "given"; + out << YAML::Value << "Dorothy"; + out << YAML::Key << "family"; + out << YAML::Value << "Gale"; + out << YAML::EndMap; + out << YAML::Key << "items"; + out << YAML::Value; + out << YAML::BeginSeq; + out << YAML::BeginMap; + out << YAML::Key << "part_no"; + out << YAML::Value << "A4786"; + out << YAML::Key << "descrip"; + out << YAML::Value << "Water Bucket (Filled)"; + out << YAML::Key << "price"; + out << YAML::Value << 1.47; + out << YAML::Key << "quantity"; + out << YAML::Value << 4; + out << YAML::EndMap; + out << YAML::BeginMap; + out << YAML::Key << "part_no"; + out << YAML::Value << "E1628"; + out << YAML::Key << "descrip"; + out << YAML::Value << "High Heeled \"Ruby\" Slippers"; + out << YAML::Key << "price"; + out << YAML::Value << 100.27; + out << YAML::Key << "quantity"; + out << YAML::Value << 1; + out << YAML::EndMap; + out << YAML::EndSeq; + out << YAML::Key << "bill-to"; + out << YAML::Value << YAML::Anchor("id001"); + out << YAML::BeginMap; + out << YAML::Key << "street"; + out << YAML::Value << YAML::Literal << "123 Tornado Alley\nSuite 16"; + out << YAML::Key << "city"; + out << YAML::Value << "East Westville"; + out << YAML::Key << "state"; + out << YAML::Value << "KS"; + out << YAML::EndMap; + out << YAML::Key << "ship-to"; + out << YAML::Value << YAML::Alias("id001"); + out << YAML::EndMap; + + desiredOutput = "receipt: Oz-Ware Purchase Invoice\ndate: 2007-08-06\ncustomer:\n given: Dorothy\n family: Gale\nitems:\n -\n part_no: A4786\n descrip: Water Bucket (Filled)\n price: 1.47\n quantity: 4\n -\n part_no: E1628\n descrip: High Heeled \"Ruby\" Slippers\n price: 100.27\n quantity: 1\nbill-to: &id001\n street: |\n 123 Tornado Alley\n Suite 16\n city: East Westville\n state: KS\nship-to: *id001"; + } + + void STLContainers(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + std::vector primes; + primes.push_back(2); + primes.push_back(3); + primes.push_back(5); + primes.push_back(7); + primes.push_back(11); + primes.push_back(13); + out << YAML::Flow << primes; + std::map ages; + ages["Daniel"] = 26; + ages["Jesse"] = 24; + out << ages; + out << YAML::EndSeq; + + desiredOutput = "- [2, 3, 5, 7, 11, 13]\n-\n Daniel: 26\n Jesse: 24"; + } + + void SimpleComment(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << "method"; + out << YAML::Value << "least squares" << YAML::Comment("should we change this method?"); + out << YAML::EndMap; + + desiredOutput = "method: least squares # should we change this method?"; + } + + void MultiLineComment(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << "item 1" << YAML::Comment("really really long\ncomment that couldn't possibly\nfit on one line"); + out << "item 2"; + out << YAML::EndSeq; + + desiredOutput = "- item 1 # really really long\n # comment that couldn't possibly\n # fit on one line\n- item 2"; + } + + void ComplexComments(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::LongKey << YAML::Key << "long key" << YAML::Comment("long key"); + out << YAML::Value << "value"; + out << YAML::EndMap; + + desiredOutput = "? long key # long key\n: value"; + } + + void Indentation(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Indent(4); + out << YAML::BeginSeq; + out << YAML::BeginMap; + out << YAML::Key << "key 1" << YAML::Value << "value 1"; + out << YAML::Key << "key 2" << YAML::Value << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; + out << YAML::EndMap; + out << YAML::EndSeq; + + desiredOutput = "-\n key 1: value 1\n key 2:\n - a\n - b\n - c"; + } + + void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) + { + out.SetIndent(4); + out.SetMapFormat(YAML::LongKey); + + out << YAML::BeginSeq; + out << YAML::BeginMap; + out << YAML::Key << "key 1" << YAML::Value << "value 1"; + out << YAML::Key << "key 2" << YAML::Value << YAML::Flow << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; + out << YAML::EndMap; + out << YAML::EndSeq; + + desiredOutput = "-\n ? key 1\n : value 1\n ? key 2\n : [a, b, c]"; + } + + void ComplexGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << YAML::Block; + out << YAML::BeginMap; + out << YAML::Key << "key 1" << YAML::Value << "value 1"; + out << YAML::Key << "key 2" << YAML::Value; + out.SetSeqFormat(YAML::Flow); + out << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; + out << YAML::EndMap; + out << YAML::BeginMap; + out << YAML::Key << YAML::BeginSeq << 1 << 2 << YAML::EndSeq; + out << YAML::Value << YAML::BeginMap << YAML::Key << "a" << YAML::Value << "b" << YAML::EndMap; + out << YAML::EndMap; + out << YAML::EndSeq; + + desiredOutput = "-\n key 1: value 1\n key 2: [a, b, c]\n-\n ? [1, 2]\n :\n a: b"; + } + + void Null(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << YAML::Null; + out << YAML::BeginMap; + out << YAML::Key << "null value" << YAML::Value << YAML::Null; + out << YAML::Key << YAML::Null << YAML::Value << "null key"; + out << YAML::EndMap; + out << YAML::EndSeq; + + desiredOutput = "- ~\n-\n null value: ~\n ~: null key"; + } + + void EscapedUnicode(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::EscapeNonAscii << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; + + desiredOutput = "\"$ \\xa2 \\u20ac \\U00024b62\""; + } + + void Unicode(YAML::Emitter& out, std::string& desiredOutput) + { + out << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; + desiredOutput = "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; + } + + void DoubleQuotedUnicode(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::DoubleQuoted << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; + desiredOutput = "\"\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2\""; + } + + + //////////////////////////////////////////////////////////////////////////////////////////////////////// + // incorrect emitting + + void ExtraEndSeq(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::UNEXPECTED_END_SEQ; + + out << YAML::BeginSeq; + out << "Hello"; + out << "World"; + out << YAML::EndSeq; + out << YAML::EndSeq; + } + + void ExtraEndMap(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::UNEXPECTED_END_MAP; + + out << YAML::BeginMap; + out << YAML::Key << "Hello" << YAML::Value << "World"; + out << YAML::EndMap; + out << YAML::EndMap; + } + + void BadSingleQuoted(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::SINGLE_QUOTED_CHAR; + + out << YAML::SingleQuoted << "Hello\nWorld"; + } + + void InvalidAnchor(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::INVALID_ANCHOR; + + out << YAML::BeginSeq; + out << YAML::Anchor("new\nline") << "Test"; + out << YAML::EndSeq; + } + + void InvalidAlias(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::INVALID_ALIAS; + + out << YAML::BeginSeq; + out << YAML::Alias("new\nline"); + out << YAML::EndSeq; + } + + void MissingKey(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::EXPECTED_KEY_TOKEN; + + out << YAML::BeginMap; + out << YAML::Key << "key" << YAML::Value << "value"; + out << "missing key" << YAML::Value << "value"; + out << YAML::EndMap; + } + + void MissingValue(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::EXPECTED_VALUE_TOKEN; + + out << YAML::BeginMap; + out << YAML::Key << "key" << "value"; + out << YAML::EndMap; + } + + void UnexpectedKey(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::UNEXPECTED_KEY_TOKEN; + + out << YAML::BeginSeq; + out << YAML::Key << "hi"; + out << YAML::EndSeq; + } + + void UnexpectedValue(YAML::Emitter& out, std::string& desiredError) + { + desiredError = YAML::ErrorMsg::UNEXPECTED_VALUE_TOKEN; + + out << YAML::BeginSeq; + out << YAML::Value << "hi"; + out << YAML::EndSeq; + } + } + + namespace { + void RunEmitterTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, int& passed, int& total) { + YAML::Emitter out; + std::string desiredOutput; + test(out, desiredOutput); + std::string output = out.c_str(); + + if(output == desiredOutput) { + passed++; + } else { + std::cout << "Emitter test failed: " << name << "\n"; + std::cout << "Output:\n"; + std::cout << output << "<<<\n"; + std::cout << "Desired output:\n"; + std::cout << desiredOutput << "<<<\n"; + } + total++; + } + + void RunEmitterErrorTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, int& passed, int& total) { + YAML::Emitter out; + std::string desiredError; + test(out, desiredError); + std::string lastError = out.GetLastError(); + if(!out.good() && lastError == desiredError) { + passed++; + } else { + std::cout << "Emitter test failed: " << name << "\n"; + if(out.good()) + std::cout << "No error detected\n"; + else + std::cout << "Detected error: " << lastError << "\n"; + std::cout << "Expected error: " << desiredError << "\n"; + } + total++; + } + } + + bool RunEmitterTests() + { + int passed = 0; + int total = 0; + RunEmitterTest(&Emitter::SimpleScalar, "simple scalar", passed, total); + RunEmitterTest(&Emitter::SimpleSeq, "simple seq", passed, total); + RunEmitterTest(&Emitter::SimpleFlowSeq, "simple flow seq", passed, total); + RunEmitterTest(&Emitter::EmptyFlowSeq, "empty flow seq", passed, total); + RunEmitterTest(&Emitter::NestedBlockSeq, "nested block seq", passed, total); + RunEmitterTest(&Emitter::NestedFlowSeq, "nested flow seq", passed, total); + RunEmitterTest(&Emitter::SimpleMap, "simple map", passed, total); + RunEmitterTest(&Emitter::SimpleFlowMap, "simple flow map", passed, total); + RunEmitterTest(&Emitter::MapAndList, "map and list", passed, total); + RunEmitterTest(&Emitter::ListAndMap, "list and map", passed, total); + RunEmitterTest(&Emitter::NestedBlockMap, "nested block map", passed, total); + RunEmitterTest(&Emitter::NestedFlowMap, "nested flow map", passed, total); + RunEmitterTest(&Emitter::MapListMix, "map list mix", passed, total); + RunEmitterTest(&Emitter::SimpleLongKey, "simple long key", passed, total); + RunEmitterTest(&Emitter::SingleLongKey, "single long key", passed, total); + RunEmitterTest(&Emitter::ComplexLongKey, "complex long key", passed, total); + RunEmitterTest(&Emitter::AutoLongKey, "auto long key", passed, total); + RunEmitterTest(&Emitter::ScalarFormat, "scalar format", passed, total); + RunEmitterTest(&Emitter::AutoLongKeyScalar, "auto long key scalar", passed, total); + RunEmitterTest(&Emitter::LongKeyFlowMap, "long key flow map", passed, total); + RunEmitterTest(&Emitter::BlockMapAsKey, "block map as key", passed, total); + RunEmitterTest(&Emitter::AliasAndAnchor, "alias and anchor", passed, total); + RunEmitterTest(&Emitter::AliasAndAnchorWithNull, "alias and anchor with null", passed, total); + RunEmitterTest(&Emitter::ComplexDoc, "complex doc", passed, total); + RunEmitterTest(&Emitter::STLContainers, "STL containers", passed, total); + RunEmitterTest(&Emitter::SimpleComment, "simple comment", passed, total); + RunEmitterTest(&Emitter::MultiLineComment, "multi-line comment", passed, total); + RunEmitterTest(&Emitter::ComplexComments, "complex comments", passed, total); + RunEmitterTest(&Emitter::Indentation, "indentation", passed, total); + RunEmitterTest(&Emitter::SimpleGlobalSettings, "simple global settings", passed, total); + RunEmitterTest(&Emitter::ComplexGlobalSettings, "complex global settings", passed, total); + RunEmitterTest(&Emitter::Null, "null", passed, total); + RunEmitterTest(&Emitter::EscapedUnicode, "escaped unicode", passed, total); + RunEmitterTest(&Emitter::Unicode, "unicode", passed, total); + RunEmitterTest(&Emitter::DoubleQuotedUnicode, "double quoted unicode", passed, total); + + RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total); + RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total); + RunEmitterErrorTest(&Emitter::BadSingleQuoted, "bad single quoted string", passed, total); + RunEmitterErrorTest(&Emitter::InvalidAnchor, "invalid anchor", passed, total); + RunEmitterErrorTest(&Emitter::InvalidAlias, "invalid alias", passed, total); + RunEmitterErrorTest(&Emitter::MissingKey, "missing key", passed, total); + RunEmitterErrorTest(&Emitter::MissingValue, "missing value", passed, total); + RunEmitterErrorTest(&Emitter::UnexpectedKey, "unexpected key", passed, total); + RunEmitterErrorTest(&Emitter::UnexpectedValue, "unexpected value", passed, total); + + std::cout << "Emitter tests: " << passed << "/" << total << " passed\n"; + return passed == total; + } +} + diff --git a/yaml-reader/emittertests.h b/yaml-reader/emittertests.h new file mode 100644 index 0000000..e746e5a --- /dev/null +++ b/yaml-reader/emittertests.h @@ -0,0 +1,11 @@ +#pragma once + +#ifndef EMITTERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define EMITTERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +namespace Test { + bool RunEmitterTests(); +} + +#endif // EMITTERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + diff --git a/yaml-reader/main.cpp b/yaml-reader/main.cpp new file mode 100644 index 0000000..881bc57 --- /dev/null +++ b/yaml-reader/main.cpp @@ -0,0 +1,11 @@ +#include "tests.h" + +int main() +{ +#ifdef WINDOWS + _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF); +#endif // WINDOWS + Test::RunAll(); + + return 0; +} diff --git a/yaml-reader/parsertests.cpp b/yaml-reader/parsertests.cpp new file mode 100644 index 0000000..138143c --- /dev/null +++ b/yaml-reader/parsertests.cpp @@ -0,0 +1,888 @@ +#include "tests.h" +#include "yaml.h" +#include +#include + +namespace Test +{ + namespace Parser { + void SimpleScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = "Hello, World!"; + desiredOutput = "Hello, World!"; + } + + void MultiLineScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = + "normal scalar, but\n" + "over several lines"; + desiredOutput = "normal scalar, but over several lines"; + } + + void LiteralScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = + "|\n" + " literal scalar - so we can draw ASCII:\n" + " \n" + " - -\n" + " | - |\n" + " -----\n"; + desiredOutput = + "literal scalar - so we can draw ASCII:\n" + "\n" + " - -\n" + " | - |\n" + " -----\n"; + } + + void FoldedScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = + ">\n" + " and a folded scalar... so we\n" + " can just keep writing various\n" + " things. And if we want to keep indentation:\n" + " \n" + " we just indent a little\n" + " see, this stays indented"; + desiredOutput = + "and a folded scalar... so we" + " can just keep writing various" + " things. And if we want to keep indentation:\n" + "\n" + " we just indent a little\n" + " see, this stays indented"; + } + + void ChompedFoldedScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = + ">-\n" + " Here's a folded scalar\n" + " that gets chomped."; + desiredOutput = + "Here's a folded scalar" + " that gets chomped."; + } + + void ChompedLiteralScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = + "|-\n" + " Here's a literal scalar\n" + " that gets chomped."; + desiredOutput = + "Here's a literal scalar\n" + "that gets chomped."; + } + + void FoldedScalarWithIndent(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = + ">2\n" + " Here's a folded scalar\n" + " that starts with some indentation."; + desiredOutput = + " Here's a folded scalar\n" + "that starts with some indentation."; + } + + void ColonScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = "::vector"; + desiredOutput = "::vector"; + } + + void QuotedScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = "\": - ()\""; + desiredOutput = ": - ()"; + } + + void CommaScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = "Up, up, and away!"; + desiredOutput = "Up, up, and away!"; + } + + void DashScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = "-123"; + desiredOutput = "-123"; + } + + void URLScalar(std::string& inputScalar, std::string& desiredOutput) + { + inputScalar = "http://example.com/foo#bar"; + desiredOutput = "http://example.com/foo#bar"; + } + + bool SimpleSeq() + { + std::string input = + "- eggs\n" + "- bread\n" + "- milk"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc[0] >> output; + if(output != "eggs") + return false; + doc[1] >> output; + if(output != "bread") + return false; + doc[2] >> output; + if(output != "milk") + return false; + + return true; + } + + bool SimpleMap() + { + std::string input = + "name: Prince Fielder\n" + "position: 1B\n" + "bats: L"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc["name"] >> output; + if(output != "Prince Fielder") + return false; + doc["position"] >> output; + if(output != "1B") + return false; + doc["bats"] >> output; + if(output != "L") + return false; + + return true; + } + + bool FlowSeq() + { + std::string input = "[ 2 , 3, 5 , 7, 11]"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + int output; + doc[0] >> output; + if(output != 2) + return false; + doc[1] >> output; + if(output != 3) + return false; + doc[2] >> output; + if(output != 5) + return false; + doc[3] >> output; + if(output != 7) + return false; + doc[4] >> output; + if(output != 11) + return false; + + return true; + } + + bool FlowMap() + { + std::string input = "{hr: 65, avg: 0.278}"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc["hr"] >> output; + if(output != "65") + return false; + doc["avg"] >> output; + if(output != "0.278") + return false; + + return true; + } + + bool FlowMapWithOmittedKey() + { + std::string input = "{: omitted key}"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc[YAML::Null] >> output; + if(output != "omitted key") + return false; + + return true; + } + + bool FlowMapWithOmittedValue() + { + std::string input = "{a: b, c:, d:}"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc["a"] >> output; + if(output != "b") + return false; + if(!IsNull(doc["c"])) + return false; + if(!IsNull(doc["d"])) + return false; + + return true; + } + + bool FlowMapWithSoloEntry() + { + std::string input = "{a: b, c, d: e}"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc["a"] >> output; + if(output != "b") + return false; + if(!IsNull(doc["c"])) + return false; + doc["d"] >> output; + if(output != "e") + return false; + + return true; + } + + bool FlowMapEndingWithSoloEntry() + { + std::string input = "{a: b, c}"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc["a"] >> output; + if(output != "b") + return false; + if(!IsNull(doc["c"])) + return false; + + return true; + } + + bool QuotedSimpleKeys() + { + std::string KeyValue[3] = { "\"double\": double\n", "'single': single\n", "plain: plain\n" }; + + int perm[3] = { 0, 1, 2 }; + do { + std::string input = KeyValue[perm[0]] + KeyValue[perm[1]] + KeyValue[perm[2]]; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc["double"] >> output; + if(output != "double") + return false; + doc["single"] >> output; + if(output != "single") + return false; + doc["plain"] >> output; + if(output != "plain") + return false; + } while(std::next_permutation(perm, perm + 3)); + + return true; + } + + bool CompressedMapAndSeq() + { + std::string input = "key:\n- one\n- two"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + const YAML::Node& seq = doc["key"]; + if(seq.size() != 2) + return false; + + std::string output; + seq[0] >> output; + if(output != "one") + return false; + seq[1] >> output; + if(output != "two") + return false; + + return true; + } + + bool NullBlockSeqEntry() + { + std::string input = "- hello\n-\n- world"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc[0] >> output; + if(output != "hello") + return false; + if(!IsNull(doc[1])) + return false; + doc[2] >> output; + if(output != "world") + return false; + + return true; + } + + bool NullBlockMapKey() + { + std::string input = ": empty key"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc[YAML::Null] >> output; + if(output != "empty key") + return false; + + return true; + } + + bool NullBlockMapValue() + { + std::string input = "empty value:"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + if(!IsNull(doc["empty value"])) + return false; + + return true; + } + + bool SimpleAlias() + { + std::string input = "- &alias test\n- *alias"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc[0] >> output; + if(output != "test") + return false; + + doc[1] >> output; + if(output != "test") + return false; + + if(doc.size() != 2) + return false; + + return true; + } + + bool AliasWithNull() + { + std::string input = "- &alias\n- *alias"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + if(!IsNull(doc[0])) + return false; + + if(!IsNull(doc[1])) + return false; + + if(doc.size() != 2) + return false; + + return true; + } + + bool AnchorInSimpleKey() + { + std::string input = "- &a b: c\n- *a"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + if(doc.size() != 2) + return false; + + std::string output; + doc[0]["b"] >> output; + if(output != "c") + return false; + + doc[1] >> output; + if(output != "b") + return false; + + return true; + } + + bool AliasAsSimpleKey() + { + std::string input = "- &a b\n- *a: c"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + if(doc.size() != 2) + return false; + + std::string output; + doc[0] >> output; + if(output != "b") + return false; + + doc[1]["b"] >> output; + if(output != "c") + return false; + + return true; + } + + bool ExplicitDoc() + { + std::string input = "---\n- one\n- two"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + if(doc.size() != 2) + return false; + + std::string output; + doc[0] >> output; + if(output != "one") + return false; + doc[1] >> output; + if(output != "two") + return false; + + return true; + } + + bool MultipleDocs() + { + std::string input = "---\nname: doc1\n---\nname: doc2"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::string output; + doc["name"] >> output; + if(output != "doc1") + return false; + + if(!parser) + return false; + + parser.GetNextDocument(doc); + doc["name"] >> output; + if(output != "doc2") + return false; + + return true; + } + + bool ExplicitEndDoc() + { + std::string input = "- one\n- two\n...\n..."; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + if(doc.size() != 2) + return false; + + std::string output; + doc[0] >> output; + if(output != "one") + return false; + doc[1] >> output; + if(output != "two") + return false; + + return true; + } + + bool MultipleDocsWithSomeExplicitIndicators() + { + std::string input = + "- one\n- two\n...\n" + "---\nkey: value\n...\n...\n" + "- three\n- four\n" + "---\nkey: value"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + std::string output; + + parser.GetNextDocument(doc); + if(doc.size() != 2) + return false; + doc[0] >> output; + if(output != "one") + return false; + doc[1] >> output; + if(output != "two") + return false; + + parser.GetNextDocument(doc); + doc["key"] >> output; + if(output != "value") + return false; + + parser.GetNextDocument(doc); + if(doc.size() != 2) + return false; + doc[0] >> output; + if(output != "three") + return false; + doc[1] >> output; + if(output != "four") + return false; + + parser.GetNextDocument(doc); + doc["key"] >> output; + if(output != "value") + return false; + + return true; + } + } + + namespace { + void RunScalarParserTest(void (*test)(std::string&, std::string&), const std::string& name, int& passed, int& total) { + std::string error; + std::string inputScalar, desiredOutput; + std::string output; + bool ok = true; + try { + test(inputScalar, desiredOutput); + std::stringstream stream(inputScalar); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + doc >> output; + } catch(const YAML::Exception& e) { + ok = false; + error = e.msg; + } + if(ok && output == desiredOutput) { + passed++; + } else { + std::cout << "Parser test failed: " << name << "\n"; + if(error != "") + std::cout << "Caught exception: " << error << "\n"; + else { + std::cout << "Output:\n" << output << "<<<\n"; + std::cout << "Desired output:\n" << desiredOutput << "<<<\n"; + } + } + total++; + } + + void RunParserTest(bool (*test)(), const std::string& name, int& passed, int& total) { + std::string error; + bool ok = true; + try { + ok = test(); + } catch(const YAML::Exception& e) { + ok = false; + error = e.msg; + } + if(ok) { + passed++; + } else { + std::cout << "Parser test failed: " << name << "\n"; + if(error != "") + std::cout << "Caught exception: " << error << "\n"; + } + total++; + } + + typedef void (*EncodingFn)(std::ostream&, int); + + inline char Byte(int ch) + { + return static_cast(static_cast(static_cast(ch))); + } + + void EncodeToUtf8(std::ostream& stream, int ch) + { + if (ch <= 0x7F) + { + stream << Byte(ch); + } + else if (ch <= 0x7FF) + { + stream << Byte(0xC0 | (ch >> 6)); + stream << Byte(0x80 | (ch & 0x3F)); + } + else if (ch <= 0xFFFF) + { + stream << Byte(0xE0 | (ch >> 12)); + stream << Byte(0x80 | ((ch >> 6) & 0x3F)); + stream << Byte(0x80 | (ch & 0x3F)); + } + else if (ch <= 0x1FFFFF) + { + stream << Byte(0xF0 | (ch >> 18)); + stream << Byte(0x80 | ((ch >> 12) & 0x3F)); + stream << Byte(0x80 | ((ch >> 6) & 0x3F)); + stream << Byte(0x80 | (ch & 0x3F)); + } + } + + bool SplitUtf16HighChar(std::ostream& stream, EncodingFn encoding, int ch) + { + int biasedValue = ch - 0x10000; + if (biasedValue < 0) + { + return false; + } + int high = 0xD800 | (biasedValue >> 10); + int low = 0xDC00 | (biasedValue & 0x3FF); + encoding(stream, high); + encoding(stream, low); + return true; + } + + void EncodeToUtf16LE(std::ostream& stream, int ch) + { + if (!SplitUtf16HighChar(stream, &EncodeToUtf16LE, ch)) + { + stream << Byte(ch & 0xFF) << Byte(ch >> 8); + } + } + + void EncodeToUtf16BE(std::ostream& stream, int ch) + { + if (!SplitUtf16HighChar(stream, &EncodeToUtf16BE, ch)) + { + stream << Byte(ch >> 8) << Byte(ch & 0xFF); + } + } + + void EncodeToUtf32LE(std::ostream& stream, int ch) + { + stream << Byte(ch & 0xFF) << Byte((ch >> 8) & 0xFF) + << Byte((ch >> 16) & 0xFF) << Byte((ch >> 24) & 0xFF); + } + + void EncodeToUtf32BE(std::ostream& stream, int ch) + { + stream << Byte((ch >> 24) & 0xFF) << Byte((ch >> 16) & 0xFF) + << Byte((ch >> 8) & 0xFF) << Byte(ch & 0xFF); + } + + class EncodingTester + { + public: + EncodingTester(EncodingFn encoding, bool declareEncoding) + { + if (declareEncoding) + { + encoding(m_yaml, 0xFEFF); + } + + AddEntry(encoding, 0x0021, 0x007E); // Basic Latin + AddEntry(encoding, 0x00A1, 0x00FF); // Latin-1 Supplement + AddEntry(encoding, 0x0660, 0x06FF); // Arabic (largest contiguous block) + + // CJK unified ideographs (multiple lines) + AddEntry(encoding, 0x4E00, 0x4EFF); + AddEntry(encoding, 0x4F00, 0x4FFF); + AddEntry(encoding, 0x5000, 0x51FF); // 512 character line + AddEntry(encoding, 0x5200, 0x54FF); // 768 character line + AddEntry(encoding, 0x5500, 0x58FF); // 1024 character line + + AddEntry(encoding, 0x103A0, 0x103C3); // Old Persian + + m_yaml.seekg(0, std::ios::beg); + } + + std::istream& stream() {return m_yaml;} + const std::vector& entries() {return m_entries;} + + private: + std::stringstream m_yaml; + std::vector m_entries; + + void AddEntry(EncodingFn encoding, int startCh, int endCh) + { + encoding(m_yaml, '-'); + encoding(m_yaml, ' '); + encoding(m_yaml, '|'); + encoding(m_yaml, '\n'); + encoding(m_yaml, ' '); + encoding(m_yaml, ' '); + + std::stringstream entry; + for (int ch = startCh; ch <= endCh; ++ch) + { + encoding(m_yaml, ch); + EncodeToUtf8(entry, ch); + } + encoding(m_yaml, '\n'); + + m_entries.push_back(entry.str()); + } + }; + + void RunEncodingTest(EncodingFn encoding, bool declareEncoding, const std::string& name, int& passed, int& total) + { + EncodingTester tester(encoding, declareEncoding); + std::string error; + bool ok = true; + try { + YAML::Parser parser(tester.stream()); + YAML::Node doc; + parser.GetNextDocument(doc); + + YAML::Iterator itNode = doc.begin(); + std::vector::const_iterator itEntry = tester.entries().begin(); + for (; (itNode != doc.end()) && (itEntry != tester.entries().end()); ++itNode, ++itEntry) + { + std::string stScalarValue; + if (!itNode->GetScalar(stScalarValue) && (stScalarValue == *itEntry)) + { + break; + } + } + + if ((itNode != doc.end()) || (itEntry != tester.entries().end())) + { + ok = false; + } + } catch(const YAML::Exception& e) { + ok = false; + error = e.msg; + } + if(ok) { + passed++; + } else { + std::cout << "Parser test failed: " << name << "\n"; + if(error != "") + std::cout << "Caught exception: " << error << "\n"; + } + total++; + } + } + + bool RunParserTests() + { + int passed = 0; + int total = 0; + RunScalarParserTest(&Parser::SimpleScalar, "simple scalar", passed, total); + RunScalarParserTest(&Parser::MultiLineScalar, "multi-line scalar", passed, total); + RunScalarParserTest(&Parser::LiteralScalar, "literal scalar", passed, total); + RunScalarParserTest(&Parser::FoldedScalar, "folded scalar", passed, total); + RunScalarParserTest(&Parser::ChompedFoldedScalar, "chomped folded scalar", passed, total); + RunScalarParserTest(&Parser::ChompedLiteralScalar, "chomped literal scalar", passed, total); + RunScalarParserTest(&Parser::FoldedScalarWithIndent, "folded scalar with indent", passed, total); + RunScalarParserTest(&Parser::ColonScalar, "colon scalar", passed, total); + RunScalarParserTest(&Parser::QuotedScalar, "quoted scalar", passed, total); + RunScalarParserTest(&Parser::CommaScalar, "comma scalar", passed, total); + RunScalarParserTest(&Parser::DashScalar, "dash scalar", passed, total); + RunScalarParserTest(&Parser::URLScalar, "url scalar", passed, total); + + RunParserTest(&Parser::SimpleSeq, "simple seq", passed, total); + RunParserTest(&Parser::SimpleMap, "simple map", passed, total); + RunParserTest(&Parser::FlowSeq, "flow seq", passed, total); + RunParserTest(&Parser::FlowMap, "flow map", passed, total); + RunParserTest(&Parser::FlowMapWithOmittedKey, "flow map with omitted key", passed, total); + RunParserTest(&Parser::FlowMapWithOmittedValue, "flow map with omitted value", passed, total); + RunParserTest(&Parser::FlowMapWithSoloEntry, "flow map with solo entry", passed, total); + RunParserTest(&Parser::FlowMapEndingWithSoloEntry, "flow map ending with solo entry", passed, total); + RunParserTest(&Parser::QuotedSimpleKeys, "quoted simple keys", passed, total); + RunParserTest(&Parser::CompressedMapAndSeq, "compressed map and seq", passed, total); + RunParserTest(&Parser::NullBlockSeqEntry, "null block seq entry", passed, total); + RunParserTest(&Parser::NullBlockMapKey, "null block map key", passed, total); + RunParserTest(&Parser::NullBlockMapValue, "null block map value", passed, total); + RunParserTest(&Parser::SimpleAlias, "simple alias", passed, total); + RunParserTest(&Parser::AliasWithNull, "alias with null", passed, total); + RunParserTest(&Parser::AnchorInSimpleKey, "anchor in simple key", passed, total); + RunParserTest(&Parser::AliasAsSimpleKey, "alias as simple key", passed, total); + RunParserTest(&Parser::ExplicitDoc, "explicit doc", passed, total); + RunParserTest(&Parser::MultipleDocs, "multiple docs", passed, total); + RunParserTest(&Parser::ExplicitEndDoc, "explicit end doc", passed, total); + RunParserTest(&Parser::MultipleDocsWithSomeExplicitIndicators, "multiple docs with some explicit indicators", passed, total); + + RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed, total); + RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed, total); + RunEncodingTest(&EncodeToUtf16LE, false, "UTF-16LE, no BOM", passed, total); + RunEncodingTest(&EncodeToUtf16LE, true, "UTF-16LE with BOM", passed, total); + RunEncodingTest(&EncodeToUtf16BE, false, "UTF-16BE, no BOM", passed, total); + RunEncodingTest(&EncodeToUtf16BE, true, "UTF-16BE with BOM", passed, total); + RunEncodingTest(&EncodeToUtf32LE, false, "UTF-32LE, no BOM", passed, total); + RunEncodingTest(&EncodeToUtf32LE, true, "UTF-32LE with BOM", passed, total); + RunEncodingTest(&EncodeToUtf32BE, false, "UTF-32BE, no BOM", passed, total); + RunEncodingTest(&EncodeToUtf32BE, true, "UTF-32BE with BOM", passed, total); + + std::cout << "Parser tests: " << passed << "/" << total << " passed\n"; + return passed == total; + } +} + diff --git a/yaml-reader/parsertests.h b/yaml-reader/parsertests.h new file mode 100644 index 0000000..e63a2eb --- /dev/null +++ b/yaml-reader/parsertests.h @@ -0,0 +1,11 @@ +#pragma once + +#ifndef PARSERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define PARSERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +namespace Test { + bool RunParserTests(); +} + +#endif // PARSERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + diff --git a/yaml-reader/spectests.cpp b/yaml-reader/spectests.cpp new file mode 100644 index 0000000..c4da43f --- /dev/null +++ b/yaml-reader/spectests.cpp @@ -0,0 +1,1280 @@ +#include "spectests.h" +#include "yaml.h" +#include +#include +#include +#include + +namespace { + struct TEST { + TEST(): ok(false) {} + TEST(bool ok_): ok(ok_) {} + TEST(const char *error_): ok(false), error(error_) {} + + bool ok; + std::string error; + }; +} + +#define YAML_ASSERT(cond) do { if(!(cond)) return " Assert failed: " #cond; } while(false) +#define PARSE(doc, input) \ + std::stringstream stream(input);\ + YAML::Parser parser(stream);\ + YAML::Node doc;\ + parser.GetNextDocument(doc) +#define PARSE_NEXT(doc) parser.GetNextDocument(doc) + +namespace Test { + namespace { + void RunSpecTest(TEST (*test)(), const std::string& index, const std::string& name, int& passed, int& total) { + TEST ret; + try { + ret = test(); + } catch(const YAML::Exception& e) { + ret.ok = false; + ret.error = " Exception caught: " + e.msg; + } + + if(!ret.ok) { + std::cout << "Spec test " << index << " failed: " << name << "\n"; + std::cout << ret.error << "\n"; + } + + if(ret.ok) + passed++; + total++; + } + } + + namespace Spec { + // 2.1 + TEST SeqScalars() { + std::string input = + "- Mark McGwire\n" + "- Sammy Sosa\n" + "- Ken Griffey"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc[0] == "Mark McGwire"); + YAML_ASSERT(doc[1] == "Sammy Sosa"); + YAML_ASSERT(doc[2] == "Ken Griffey"); + return true; + } + + // 2.2 + TEST MappingScalarsToScalars() { + std::string input = + "hr: 65 # Home runs\n" + "avg: 0.278 # Batting average\n" + "rbi: 147 # Runs Batted In"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["hr"] == "65"); + YAML_ASSERT(doc["avg"] == "0.278"); + YAML_ASSERT(doc["rbi"] == "147"); + return true; + } + + // 2.3 + TEST MappingScalarsToSequences() { + std::string input = + "american:\n" + "- Boston Red Sox\n" + "- Detroit Tigers\n" + "- New York Yankees\n" + "national:\n" + "- New York Mets\n" + "- Chicago Cubs\n" + "- Atlanta Braves"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["american"].size() == 3); + YAML_ASSERT(doc["american"][0] == "Boston Red Sox"); + YAML_ASSERT(doc["american"][1] == "Detroit Tigers"); + YAML_ASSERT(doc["american"][2] == "New York Yankees"); + YAML_ASSERT(doc["national"].size() == 3); + YAML_ASSERT(doc["national"][0] == "New York Mets"); + YAML_ASSERT(doc["national"][1] == "Chicago Cubs"); + YAML_ASSERT(doc["national"][2] == "Atlanta Braves"); + return true; + } + + // 2.4 + TEST SequenceOfMappings() + { + std::string input = + "-\n" + " name: Mark McGwire\n" + " hr: 65\n" + " avg: 0.278\n" + "-\n" + " name: Sammy Sosa\n" + " hr: 63\n" + " avg: 0.288"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc[0].size() == 3); + YAML_ASSERT(doc[0]["name"] == "Mark McGwire"); + YAML_ASSERT(doc[0]["hr"] == "65"); + YAML_ASSERT(doc[0]["avg"] == "0.278"); + YAML_ASSERT(doc[1].size() == 3); + YAML_ASSERT(doc[1]["name"] == "Sammy Sosa"); + YAML_ASSERT(doc[1]["hr"] == "63"); + YAML_ASSERT(doc[1]["avg"] == "0.288"); + return true; + } + + // 2.5 + TEST SequenceOfSequences() + { + std::string input = + "- [name , hr, avg ]\n" + "- [Mark McGwire, 65, 0.278]\n" + "- [Sammy Sosa , 63, 0.288]"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc[0].size() == 3); + YAML_ASSERT(doc[0][0] == "name"); + YAML_ASSERT(doc[0][1] == "hr"); + YAML_ASSERT(doc[0][2] == "avg"); + YAML_ASSERT(doc[1].size() == 3); + YAML_ASSERT(doc[1][0] == "Mark McGwire"); + YAML_ASSERT(doc[1][1] == "65"); + YAML_ASSERT(doc[1][2] == "0.278"); + YAML_ASSERT(doc[2].size() == 3); + YAML_ASSERT(doc[2][0] == "Sammy Sosa"); + YAML_ASSERT(doc[2][1] == "63"); + YAML_ASSERT(doc[2][2] == "0.288"); + return true; + } + + // 2.6 + TEST MappingOfMappings() + { + std::string input = + "Mark McGwire: {hr: 65, avg: 0.278}\n" + "Sammy Sosa: {\n" + " hr: 63,\n" + " avg: 0.288\n" + " }"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["Mark McGwire"].size() == 2); + YAML_ASSERT(doc["Mark McGwire"]["hr"] == "65"); + YAML_ASSERT(doc["Mark McGwire"]["avg"] == "0.278"); + YAML_ASSERT(doc["Sammy Sosa"].size() == 2); + YAML_ASSERT(doc["Sammy Sosa"]["hr"] == "63"); + YAML_ASSERT(doc["Sammy Sosa"]["avg"] == "0.288"); + return true; + } + + // 2.7 + TEST TwoDocumentsInAStream() + { + std::string input = + "# Ranking of 1998 home runs\n" + "---\n" + "- Mark McGwire\n" + "- Sammy Sosa\n" + "- Ken Griffey\n" + "\n" + "# Team ranking\n" + "---\n" + "- Chicago Cubs\n" + "- St Louis Cardinals"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc[0] == "Mark McGwire"); + YAML_ASSERT(doc[1] == "Sammy Sosa"); + YAML_ASSERT(doc[2] == "Ken Griffey"); + + PARSE_NEXT(doc); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc[0] == "Chicago Cubs"); + YAML_ASSERT(doc[1] == "St Louis Cardinals"); + return true; + } + + // 2.8 + TEST PlayByPlayFeed() + { + std::string input = + "---\n" + "time: 20:03:20\n" + "player: Sammy Sosa\n" + "action: strike (miss)\n" + "...\n" + "---\n" + "time: 20:03:47\n" + "player: Sammy Sosa\n" + "action: grand slam\n" + "..."; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["time"] == "20:03:20"); + YAML_ASSERT(doc["player"] == "Sammy Sosa"); + YAML_ASSERT(doc["action"] == "strike (miss)"); + + PARSE_NEXT(doc); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["time"] == "20:03:47"); + YAML_ASSERT(doc["player"] == "Sammy Sosa"); + YAML_ASSERT(doc["action"] == "grand slam"); + return true; + } + + // 2.9 + TEST SingleDocumentWithTwoComments() + { + std::string input = + "---\n" + "hr: # 1998 hr ranking\n" + " - Mark McGwire\n" + " - Sammy Sosa\n" + "rbi:\n" + " # 1998 rbi ranking\n" + " - Sammy Sosa\n" + " - Ken Griffey"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["hr"].size() == 2); + YAML_ASSERT(doc["hr"][0] == "Mark McGwire"); + YAML_ASSERT(doc["hr"][1] == "Sammy Sosa"); + YAML_ASSERT(doc["rbi"].size() == 2); + YAML_ASSERT(doc["rbi"][0] == "Sammy Sosa"); + YAML_ASSERT(doc["rbi"][1] == "Ken Griffey"); + return true; + } + + // 2.10 + TEST SimpleAnchor() + { + std::string input = + "---\n" + "hr:\n" + " - Mark McGwire\n" + " # Following node labeled SS\n" + " - &SS Sammy Sosa\n" + "rbi:\n" + " - *SS # Subsequent occurrence\n" + " - Ken Griffey"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["hr"].size() == 2); + YAML_ASSERT(doc["hr"][0] == "Mark McGwire"); + YAML_ASSERT(doc["hr"][1] == "Sammy Sosa"); + YAML_ASSERT(doc["rbi"].size() == 2); + YAML_ASSERT(doc["rbi"][0] == "Sammy Sosa"); + YAML_ASSERT(doc["rbi"][1] == "Ken Griffey"); + return true; + } + + struct Pair { + Pair() {} + Pair(const std::string& f, const std::string& s): first(f), second(s) {} + std::string first, second; + }; + + bool operator == (const Pair& p, const Pair& q) { + return p.first == q.first && p.second == q.second; + } + + void operator >> (const YAML::Node& node, Pair& p) { + node[0] >> p.first; + node[1] >> p.second; + } + + // 2.11 + TEST MappingBetweenSequences() + { + std::string input = + "? - Detroit Tigers\n" + " - Chicago cubs\n" + ":\n" + " - 2001-07-23\n" + "\n" + "? [ New York Yankees,\n" + " Atlanta Braves ]\n" + ": [ 2001-07-02, 2001-08-12,\n" + " 2001-08-14 ]"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc[Pair("Detroit Tigers", "Chicago cubs")].size() == 1); + YAML_ASSERT(doc[Pair("Detroit Tigers", "Chicago cubs")][0] == "2001-07-23"); + YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")].size() == 3); + YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][0] == "2001-07-02"); + YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][1] == "2001-08-12"); + YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][2] == "2001-08-14"); + return true; + } + + // 2.12 + TEST CompactNestedMapping() + { + std::string input = + "---\n" + "# Products purchased\n" + "- item : Super Hoop\n" + " quantity: 1\n" + "- item : Basketball\n" + " quantity: 4\n" + "- item : Big Shoes\n" + " quantity: 1"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc[0].size() == 2); + YAML_ASSERT(doc[0]["item"] == "Super Hoop"); + YAML_ASSERT(doc[0]["quantity"] == 1); + YAML_ASSERT(doc[1].size() == 2); + YAML_ASSERT(doc[1]["item"] == "Basketball"); + YAML_ASSERT(doc[1]["quantity"] == 4); + YAML_ASSERT(doc[2].size() == 2); + YAML_ASSERT(doc[2]["item"] == "Big Shoes"); + YAML_ASSERT(doc[2]["quantity"] == 1); + return true; + } + + // 2.13 + TEST InLiteralsNewlinesArePreserved() + { + std::string input = + "# ASCII Art\n" + "--- |\n" + " \\//||\\/||\n" + " // || ||__"; + + PARSE(doc, input); + YAML_ASSERT(doc == + "\\//||\\/||\n" + "// || ||__"); + return true; + } + + // 2.14 + TEST InFoldedScalarsNewlinesBecomeSpaces() + { + std::string input = + "--- >\n" + " Mark McGwire's\n" + " year was crippled\n" + " by a knee injury."; + + PARSE(doc, input); + YAML_ASSERT(doc == "Mark McGwire's year was crippled by a knee injury."); + return true; + } + + // 2.15 + TEST FoldedNewlinesArePreservedForMoreIndentedAndBlankLines() + { + std::string input = + ">\n" + " Sammy Sosa completed another\n" + " fine season with great stats.\n" + " \n" + " 63 Home Runs\n" + " 0.288 Batting Average\n" + " \n" + " What a year!"; + + PARSE(doc, input); + YAML_ASSERT(doc == + "Sammy Sosa completed another fine season with great stats.\n\n" + " 63 Home Runs\n" + " 0.288 Batting Average\n\n" + "What a year!"); + return true; + } + + // 2.16 + TEST IndentationDeterminesScope() + { + std::string input = + "name: Mark McGwire\n" + "accomplishment: >\n" + " Mark set a major league\n" + " home run record in 1998.\n" + "stats: |\n" + " 65 Home Runs\n" + " 0.278 Batting Average\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["name"] == "Mark McGwire"); + YAML_ASSERT(doc["accomplishment"] == "Mark set a major league home run record in 1998.\n"); + YAML_ASSERT(doc["stats"] == "65 Home Runs\n0.278 Batting Average\n"); + return true; + } + + // 2.17 + TEST QuotedScalars() + { + std::string input = + "unicode: \"Sosa did fine.\\u263A\"\n" + "control: \"\\b1998\\t1999\\t2000\\n\"\n" + "hex esc: \"\\x0d\\x0a is \\r\\n\"\n" + "\n" + "single: '\"Howdy!\" he cried.'\n" + "quoted: ' # Not a ''comment''.'\n" + "tie-fighter: '|\\-*-/|'"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 6); + YAML_ASSERT(doc["unicode"] == "Sosa did fine.\xe2\x98\xba"); + YAML_ASSERT(doc["control"] == "\b1998\t1999\t2000\n"); + YAML_ASSERT(doc["hex esc"] == "\x0d\x0a is \r\n"); + YAML_ASSERT(doc["single"] == "\"Howdy!\" he cried."); + YAML_ASSERT(doc["quoted"] == " # Not a 'comment'."); + YAML_ASSERT(doc["tie-fighter"] == "|\\-*-/|"); + return true; + } + + // 2.18 + TEST MultiLineFlowScalars() + { + std::string input = + "plain:\n" + " This unquoted scalar\n" + " spans many lines.\n" + "\n" + "quoted: \"So does this\n" + " quoted scalar.\\n\""; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["plain"] == "This unquoted scalar spans many lines."); + YAML_ASSERT(doc["quoted"] == "So does this quoted scalar.\n"); + return true; + } + + // TODO: 2.19 - 2.26 tags + + // 2.27 + TEST Invoice() + { + std::string input = + "--- !\n" + "invoice: 34843\n" + "date : 2001-01-23\n" + "bill-to: &id001\n" + " given : Chris\n" + " family : Dumars\n" + " address:\n" + " lines: |\n" + " 458 Walkman Dr.\n" + " Suite #292\n" + " city : Royal Oak\n" + " state : MI\n" + " postal : 48046\n" + "ship-to: *id001\n" + "product:\n" + " - sku : BL394D\n" + " quantity : 4\n" + " description : Basketball\n" + " price : 450.00\n" + " - sku : BL4438H\n" + " quantity : 1\n" + " description : Super Hoop\n" + " price : 2392.00\n" + "tax : 251.42\n" + "total: 4443.52\n" + "comments:\n" + " Late afternoon is best.\n" + " Backup contact is Nancy\n" + " Billsmer @ 338-4338."; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 8); + YAML_ASSERT(doc["invoice"] == 34843); + YAML_ASSERT(doc["date"] == "2001-01-23"); + YAML_ASSERT(doc["bill-to"].size() == 3); + YAML_ASSERT(doc["bill-to"]["given"] == "Chris"); + YAML_ASSERT(doc["bill-to"]["family"] == "Dumars"); + YAML_ASSERT(doc["bill-to"]["address"].size() == 4); + YAML_ASSERT(doc["bill-to"]["address"]["lines"] == "458 Walkman Dr.\nSuite #292\n"); + YAML_ASSERT(doc["bill-to"]["address"]["city"] == "Royal Oak"); + YAML_ASSERT(doc["bill-to"]["address"]["state"] == "MI"); + YAML_ASSERT(doc["bill-to"]["address"]["postal"] == "48046"); + YAML_ASSERT(doc["ship-to"].size() == 3); + YAML_ASSERT(doc["ship-to"]["given"] == "Chris"); + YAML_ASSERT(doc["ship-to"]["family"] == "Dumars"); + YAML_ASSERT(doc["ship-to"]["address"].size() == 4); + YAML_ASSERT(doc["ship-to"]["address"]["lines"] == "458 Walkman Dr.\nSuite #292\n"); + YAML_ASSERT(doc["ship-to"]["address"]["city"] == "Royal Oak"); + YAML_ASSERT(doc["ship-to"]["address"]["state"] == "MI"); + YAML_ASSERT(doc["ship-to"]["address"]["postal"] == "48046"); + YAML_ASSERT(doc["product"].size() == 2); + YAML_ASSERT(doc["product"][0].size() == 4); + YAML_ASSERT(doc["product"][0]["sku"] == "BL394D"); + YAML_ASSERT(doc["product"][0]["quantity"] == 4); + YAML_ASSERT(doc["product"][0]["description"] == "Basketball"); + YAML_ASSERT(doc["product"][0]["price"] == "450.00"); + YAML_ASSERT(doc["product"][1].size() == 4); + YAML_ASSERT(doc["product"][1]["sku"] == "BL4438H"); + YAML_ASSERT(doc["product"][1]["quantity"] == 1); + YAML_ASSERT(doc["product"][1]["description"] == "Super Hoop"); + YAML_ASSERT(doc["product"][1]["price"] == "2392.00"); + YAML_ASSERT(doc["tax"] == "251.42"); + YAML_ASSERT(doc["total"] == "4443.52"); + YAML_ASSERT(doc["comments"] == "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338."); + return true; + } + + // 2.28 + TEST LogFile() + { + std::string input = + "---\n" + "Time: 2001-11-23 15:01:42 -5\n" + "User: ed\n" + "Warning:\n" + " This is an error message\n" + " for the log file\n" + "---\n" + "Time: 2001-11-23 15:02:31 -5\n" + "User: ed\n" + "Warning:\n" + " A slightly different error\n" + " message.\n" + "---\n" + "Date: 2001-11-23 15:03:17 -5\n" + "User: ed\n" + "Fatal:\n" + " Unknown variable \"bar\"\n" + "Stack:\n" + " - file: TopClass.py\n" + " line: 23\n" + " code: |\n" + " x = MoreObject(\"345\\n\")\n" + " - file: MoreClass.py\n" + " line: 58\n" + " code: |-\n" + " foo = bar"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["Time"] == "2001-11-23 15:01:42 -5"); + YAML_ASSERT(doc["User"] == "ed"); + YAML_ASSERT(doc["Warning"] == "This is an error message for the log file"); + + PARSE_NEXT(doc); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["Time"] == "2001-11-23 15:02:31 -5"); + YAML_ASSERT(doc["User"] == "ed"); + YAML_ASSERT(doc["Warning"] == "A slightly different error message."); + + PARSE_NEXT(doc); + YAML_ASSERT(doc.size() == 4); + YAML_ASSERT(doc["Date"] == "2001-11-23 15:03:17 -5"); + YAML_ASSERT(doc["User"] == "ed"); + YAML_ASSERT(doc["Fatal"] == "Unknown variable \"bar\""); + YAML_ASSERT(doc["Stack"].size() == 2); + YAML_ASSERT(doc["Stack"][0].size() == 3); + YAML_ASSERT(doc["Stack"][0]["file"] == "TopClass.py"); + YAML_ASSERT(doc["Stack"][0]["line"] == "23"); + YAML_ASSERT(doc["Stack"][0]["code"] == "x = MoreObject(\"345\\n\")\n"); + YAML_ASSERT(doc["Stack"][1].size() == 3); + YAML_ASSERT(doc["Stack"][1]["file"] == "MoreClass.py"); + YAML_ASSERT(doc["Stack"][1]["line"] == "58"); + YAML_ASSERT(doc["Stack"][1]["code"] == "foo = bar"); + return true; + } + + // TODO: 5.1 - 5.2 BOM + + // 5.3 + TEST BlockStructureIndicators() + { + std::string input = + "sequence:\n" + "- one\n" + "- two\n" + "mapping:\n" + " ? sky\n" + " : blue\n" + " sea : green"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["sequence"].size() == 2); + YAML_ASSERT(doc["sequence"][0] == "one"); + YAML_ASSERT(doc["sequence"][1] == "two"); + YAML_ASSERT(doc["mapping"].size() == 2); + YAML_ASSERT(doc["mapping"]["sky"] == "blue"); + YAML_ASSERT(doc["mapping"]["sea"] == "green"); + return true; + } + + // 5.4 + TEST FlowStructureIndicators() + { + std::string input = + "sequence: [ one, two, ]\n" + "mapping: { sky: blue, sea: green }"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["sequence"].size() == 2); + YAML_ASSERT(doc["sequence"][0] == "one"); + YAML_ASSERT(doc["sequence"][1] == "two"); + YAML_ASSERT(doc["mapping"].size() == 2); + YAML_ASSERT(doc["mapping"]["sky"] == "blue"); + YAML_ASSERT(doc["mapping"]["sea"] == "green"); + return true; + } + + // TODO: 5.5 comment only + + // 5.6 + TEST NodePropertyIndicators() + { + std::string input = + "anchored: !local &anchor value\n" + "alias: *anchor"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["anchored"] == "value"); // TODO: assert tag + YAML_ASSERT(doc["alias"] == "value"); + return true; + } + + // 5.7 + TEST BlockScalarIndicators() + { + std::string input = + "literal: |\n" + " some\n" + " text\n" + "folded: >\n" + " some\n" + " text\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["literal"] == "some\ntext\n"); + YAML_ASSERT(doc["folded"] == "some text\n"); + return true; + } + + // 5.8 + TEST QuotedScalarIndicators() + { + std::string input = + "single: 'text'\n" + "double: \"text\""; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["single"] == "text"); + YAML_ASSERT(doc["double"] == "text"); + return true; + } + + // TODO: 5.9 directive + // TODO: 5.10 reserved indicator + + // 5.11 + TEST LineBreakCharacters() + { + std::string input = + "|\n" + " Line break (no glyph)\n" + " Line break (glyphed)\n"; + + PARSE(doc, input); + YAML_ASSERT(doc == "Line break (no glyph)\nLine break (glyphed)\n"); + return true; + } + + // 5.12 + TEST TabsAndSpaces() + { + std::string input = + "# Tabs and spaces\n" + "quoted: \"Quoted\t\"\n" + "block: |\n" + " void main() {\n" + " \tprintf(\"Hello, world!\\n\");\n" + " }"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["quoted"] == "Quoted\t"); + YAML_ASSERT(doc["block"] == + "void main() {\n" + "\tprintf(\"Hello, world!\\n\");\n" + "}"); + return true; + } + + // 5.13 + TEST EscapedCharacters() + { + std::string input = + "\"Fun with \\\\\n" + "\\\" \\a \\b \\e \\f \\\n" + "\\n \\r \\t \\v \\0 \\\n" + "\\ \\_ \\N \\L \\P \\\n" + "\\x41 \\u0041 \\U00000041\""; + + PARSE(doc, input); + YAML_ASSERT(doc == "Fun with \x5C \x22 \x07 \x08 \x1B \x0C \x0A \x0D \x09 \x0B " + std::string("\x00", 1) + " \x20 \xA0 \x85 \xe2\x80\xa8 \xe2\x80\xa9 A A A"); + return true; + } + + // 5.14 + TEST InvalidEscapedCharacters() + { + std::string input = + "Bad escapes:\n" + " \"\\c\n" + " \\xq-\""; + + std::stringstream stream(input); + try { + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + } catch(const YAML::ParserException& e) { + YAML_ASSERT(e.msg == YAML::ErrorMsg::INVALID_ESCAPE + "c"); + return true; + } + + return false; + } + + // 6.1 + TEST IndentationSpaces() + { + std::string input = + " # Leading comment line spaces are\n" + " # neither content nor indentation.\n" + " \n" + "Not indented:\n" + " By one space: |\n" + " By four\n" + " spaces\n" + " Flow style: [ # Leading spaces\n" + " By two, # in flow style\n" + " Also by two, # are neither\n" + " \tStill by two # content nor\n" + " ] # indentation."; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc["Not indented"].size() == 2); + YAML_ASSERT(doc["Not indented"]["By one space"] == "By four\n spaces\n"); + YAML_ASSERT(doc["Not indented"]["Flow style"].size() == 3); + YAML_ASSERT(doc["Not indented"]["Flow style"][0] == "By two"); + YAML_ASSERT(doc["Not indented"]["Flow style"][1] == "Also by two"); + YAML_ASSERT(doc["Not indented"]["Flow style"][2] == "Still by two"); + return true; + } + + // 6.2 + TEST IndentationIndicators() + { + std::string input = + "? a\n" + ": -\tb\n" + " - -\tc\n" + " - d"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc["a"].size() == 2); + YAML_ASSERT(doc["a"][0] == "b"); + YAML_ASSERT(doc["a"][1].size() == 2); + YAML_ASSERT(doc["a"][1][0] == "c"); + YAML_ASSERT(doc["a"][1][1] == "d"); + return true; + } + + // 6.3 + TEST SeparationSpaces() + { + std::string input = + "- foo:\t bar\n" + "- - baz\n" + " -\tbaz"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc[0].size() == 1); + YAML_ASSERT(doc[0]["foo"] == "bar"); + YAML_ASSERT(doc[1].size() == 2); + YAML_ASSERT(doc[1][0] == "baz"); + YAML_ASSERT(doc[1][1] == "baz"); + return true; + } + + // 6.4 + TEST LinePrefixes() + { + std::string input = + "plain: text\n" + " lines\n" + "quoted: \"text\n" + " \tlines\"\n" + "block: |\n" + " text\n" + " \tlines\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["plain"] == "text lines"); + YAML_ASSERT(doc["quoted"] == "text lines"); + YAML_ASSERT(doc["block"] == "text\n \tlines\n"); + return true; + } + + // 6.5 + TEST EmptyLines() + { + std::string input = + "Folding:\n" + " \"Empty line\n" + " \t\n" + " as a line feed\"\n" + "Chomping: |\n" + " Clipped empty lines\n" + " "; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["Folding"] == "Empty line\nas a line feed"); + YAML_ASSERT(doc["Chomping"] == "Clipped empty lines\n"); + return true; + } + + // 6.6 + TEST LineFolding() + { + std::string input = + ">-\n" + " trimmed\n" + " \n" + " \n" + "\n" + " as\n" + " space"; + + PARSE(doc, input); + YAML_ASSERT(doc == "trimmed\n\n\nas space"); + return true; + } + + // 6.7 + TEST BlockFolding() + { + std::string input = + ">\n" + " foo \n" + " \n" + " \t bar\n" + "\n" + " baz\n"; + + PARSE(doc, input); + YAML_ASSERT(doc == "foo \n\n\t bar\n\nbaz\n"); + return true; + } + + // 6.8 + TEST FlowFolding() + { + std::string input = + "\"\n" + " foo \n" + " \n" + " \t bar\n" + "\n" + " baz\n" + "\""; + + PARSE(doc, input); + YAML_ASSERT(doc == " foo\nbar\nbaz "); + return true; + } + + // 6.9 + TEST SeparatedComment() + { + std::string input = + "key: # Comment\n" + " value"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc["key"] == "value"); + return true; + } + + // 6.10 + TEST CommentLines() + { + std::string input = + " # Comment\n" + " \n" + "\n"; + std::stringstream stream(input); + YAML::Parser parser(stream); + + YAML_ASSERT(!parser); + return true; + } + + // 6.11 + TEST MultiLineComments() + { + std::string input = + "key: # Comment\n" + " # lines\n" + " value\n" + "\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc["key"] == "value"); + return true; + } + + struct StringMap { + typedef std::map Map; + Map _; + }; + + bool operator == (const StringMap& m, const StringMap& n) { + return m._ == n._; + } + + void operator >> (const YAML::Node& node, StringMap& m) { + m._.clear(); + for(YAML::Iterator it=node.begin();it!=node.end();++it) { + std::string key = it.first(); + std::string value = it.second(); + m._[key] = value; + } + } + + + // 6.12 + TEST SeparationSpacesII() + { + std::string input = + "{ first: Sammy, last: Sosa }:\n" + "# Statistics:\n" + " hr: # Home runs\n" + " 65\n" + " avg: # Average\n" + " 0.278"; + + PARSE(doc, input); + StringMap key; + key._["first"] = "Sammy"; + key._["last"] = "Sosa"; + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc[key].size() == 2); + YAML_ASSERT(doc[key]["hr"] == 65); + YAML_ASSERT(doc[key]["avg"] == "0.278"); + return true; + } + + // TODO: 6.13 - 6.17 directives + // TODO: 6.18 - 6.28 tags + + // 6.29 + TEST NodeAnchors() + { + std::string input = + "First occurrence: &anchor Value\n" + "Second occurrence: *anchor"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["First occurrence"] == "Value"); + YAML_ASSERT(doc["Second occurrence"] == "Value"); + return true; + } + + // 7.1 + TEST AliasNodes() + { + std::string input = + "First occurrence: &anchor Foo\n" + "Second occurrence: *anchor\n" + "Override anchor: &anchor Bar\n" + "Reuse anchor: *anchor"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 4); + YAML_ASSERT(doc["First occurrence"] == "Foo"); + YAML_ASSERT(doc["Second occurrence"] == "Foo"); + YAML_ASSERT(doc["Override anchor"] == "Bar"); + YAML_ASSERT(doc["Reuse anchor"] == "Bar"); + return true; + } + + // 7.2 + TEST EmptyNodes() + { + std::string input = + "{\n" + " foo : !!str,\n" + " !!str : bar,\n" + "}"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["foo"] == ""); // TODO: check tag + YAML_ASSERT(doc[""] == "bar"); + return true; + } + + // 7.3 + TEST CompletelyEmptyNodes() + { + std::string input = + "{\n" + " ? foo :,\n" + " : bar,\n" + "}\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(IsNull(doc["foo"])); + YAML_ASSERT(doc[YAML::Null] == "bar"); + return true; + } + + // 7.4 + TEST DoubleQuotedImplicitKeys() + { + std::string input = + "\"implicit block key\" : [\n" + " \"implicit flow key\" : value,\n" + " ]"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc["implicit block key"].size() == 1); + YAML_ASSERT(doc["implicit block key"][0].size() == 1); + YAML_ASSERT(doc["implicit block key"][0]["implicit flow key"] == "value"); + return true; + } + + // 7.5 + TEST DoubleQuotedLineBreaks() + { + std::string input = + "\"folded \n" + "to a space,\t\n" + " \n" + "to a line feed, or \t\\\n" + " \\ \tnon-content\""; + + PARSE(doc, input); + YAML_ASSERT(doc == "folded to a space,\nto a line feed, or \t \tnon-content"); + return true; + } + + // 7.6 + TEST DoubleQuotedLines() + { + std::string input = + "\" 1st non-empty\n" + "\n" + " 2nd non-empty \n" + "\t3rd non-empty \""; + + PARSE(doc, input); + YAML_ASSERT(doc == " 1st non-empty\n2nd non-empty 3rd non-empty "); + return true; + } + + // 7.7 + TEST SingleQuotedCharacters() + { + std::string input = " 'here''s to \"quotes\"'"; + + PARSE(doc, input); + YAML_ASSERT(doc == "here's to \"quotes\""); + return true; + } + + // 7.8 + TEST SingleQuotedImplicitKeys() + { + std::string input = + "'implicit block key' : [\n" + " 'implicit flow key' : value,\n" + " ]"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc["implicit block key"].size() == 1); + YAML_ASSERT(doc["implicit block key"][0].size() == 1); + YAML_ASSERT(doc["implicit block key"][0]["implicit flow key"] == "value"); + return true; + } + + // 7.9 + TEST SingleQuotedLines() + { + std::string input = + "' 1st non-empty\n" + "\n" + " 2nd non-empty \n" + "\t3rd non-empty '"; + + PARSE(doc, input); + YAML_ASSERT(doc == " 1st non-empty\n2nd non-empty 3rd non-empty "); + return true; + } + + // 7.10 + TEST PlainCharacters() + { + std::string input = + "# Outside flow collection:\n" + "- ::vector\n" + "- \": - ()\"\n" + "- Up, up, and away!\n" + "- -123\n" + "- http://example.com/foo#bar\n" + "# Inside flow collection:\n" + "- [ ::vector,\n" + " \": - ()\",\n" + " \"Up, up, and away!\",\n" + " -123,\n" + " http://example.com/foo#bar ]"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 6); + YAML_ASSERT(doc[0] == "::vector"); + YAML_ASSERT(doc[1] == ": - ()"); + YAML_ASSERT(doc[2] == "Up, up, and away!"); + YAML_ASSERT(doc[3] == -123); + YAML_ASSERT(doc[4] == "http://example.com/foo#bar"); + YAML_ASSERT(doc[5].size() == 5); + YAML_ASSERT(doc[5][0] == "::vector"); + YAML_ASSERT(doc[5][1] == ": - ()"); + YAML_ASSERT(doc[5][2] == "Up, up, and away!"); + YAML_ASSERT(doc[5][3] == -123); + YAML_ASSERT(doc[5][4] == "http://example.com/foo#bar"); + return true; + } + + // 7.11 + TEST PlainImplicitKeys() + { + std::string input = + "implicit block key : [\n" + " implicit flow key : value,\n" + " ]"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc["implicit block key"].size() == 1); + YAML_ASSERT(doc["implicit block key"][0].size() == 1); + YAML_ASSERT(doc["implicit block key"][0]["implicit flow key"] == "value"); + return true; + } + + // 7.12 + TEST PlainLines() + { + std::string input = + "1st non-empty\n" + "\n" + " 2nd non-empty \n" + "\t3rd non-empty"; + + PARSE(doc, input); + YAML_ASSERT(doc == "1st non-empty\n2nd non-empty 3rd non-empty"); + return true; + } + } + + bool RunSpecTests() + { + int passed = 0; + int total = 0; + RunSpecTest(&Spec::SeqScalars, "2.1", "Sequence of Scalars", passed, total); + RunSpecTest(&Spec::MappingScalarsToScalars, "2.2", "Mapping Scalars to Scalars", passed, total); + RunSpecTest(&Spec::MappingScalarsToSequences, "2.3", "Mapping Scalars to Sequences", passed, total); + RunSpecTest(&Spec::SequenceOfMappings, "2.4", "Sequence of Mappings", passed, total); + RunSpecTest(&Spec::SequenceOfSequences, "2.5", "Sequence of Sequences", passed, total); + RunSpecTest(&Spec::MappingOfMappings, "2.6", "Mapping of Mappings", passed, total); + RunSpecTest(&Spec::TwoDocumentsInAStream, "2.7", "Two Documents in a Stream", passed, total); + RunSpecTest(&Spec::PlayByPlayFeed, "2.8", "Play by Play Feed from a Game", passed, total); + RunSpecTest(&Spec::SingleDocumentWithTwoComments, "2.9", "Single Document with Two Comments", passed, total); + RunSpecTest(&Spec::SimpleAnchor, "2.10", "Node for \"Sammy Sosa\" appears twice in this document", passed, total); + RunSpecTest(&Spec::MappingBetweenSequences, "2.11", "Mapping between Sequences", passed, total); + RunSpecTest(&Spec::CompactNestedMapping, "2.12", "Compact Nested Mapping", passed, total); + RunSpecTest(&Spec::InLiteralsNewlinesArePreserved, "2.13", "In literals, newlines are preserved", passed, total); + RunSpecTest(&Spec::InFoldedScalarsNewlinesBecomeSpaces, "2.14", "In folded scalars, newlines become spaces", passed, total); + RunSpecTest(&Spec::FoldedNewlinesArePreservedForMoreIndentedAndBlankLines, "2.15", "Folded newlines are preserved for \"more indented\" and blank lines", passed, total); + RunSpecTest(&Spec::IndentationDeterminesScope, "2.16", "Indentation determines scope", passed, total); + RunSpecTest(&Spec::QuotedScalars, "2.17", "Quoted scalars", passed, total); + RunSpecTest(&Spec::MultiLineFlowScalars, "2.18", "Multi-line flow scalars", passed, total); + + RunSpecTest(&Spec::Invoice, "2.27", "Invoice", passed, total); + RunSpecTest(&Spec::LogFile, "2.28", "Log File", passed, total); + + RunSpecTest(&Spec::BlockStructureIndicators, "5.3", "Block Structure Indicators", passed, total); + RunSpecTest(&Spec::FlowStructureIndicators, "5.4", "Flow Structure Indicators", passed, total); + RunSpecTest(&Spec::NodePropertyIndicators, "5.6", "Node Property Indicators", passed, total); + RunSpecTest(&Spec::BlockScalarIndicators, "5.7", "Block Scalar Indicators", passed, total); + RunSpecTest(&Spec::QuotedScalarIndicators, "5.8", "Quoted Scalar Indicators", passed, total); + RunSpecTest(&Spec::LineBreakCharacters, "5.11", "Line Break Characters", passed, total); + RunSpecTest(&Spec::TabsAndSpaces, "5.12", "Tabs and Spaces", passed, total); + RunSpecTest(&Spec::EscapedCharacters, "5.13", "Escaped Characters", passed, total); + RunSpecTest(&Spec::InvalidEscapedCharacters, "5.14", "Invalid Escaped Characters", passed, total); + + RunSpecTest(&Spec::IndentationSpaces, "6.1", "Indentation Spaces", passed, total); + RunSpecTest(&Spec::IndentationIndicators, "6.2", "Indentation Indicators", passed, total); + RunSpecTest(&Spec::SeparationSpaces, "6.3", "Separation Spaces", passed, total); + RunSpecTest(&Spec::LinePrefixes, "6.4", "Line Prefixes", passed, total); + RunSpecTest(&Spec::EmptyLines, "6.5", "Empty Lines", passed, total); + RunSpecTest(&Spec::LineFolding, "6.6", "Line Folding", passed, total); + RunSpecTest(&Spec::BlockFolding, "6.7", "Block Folding", passed, total); + RunSpecTest(&Spec::FlowFolding, "6.8", "Flow Folding", passed, total); + RunSpecTest(&Spec::SeparatedComment, "6.9", "Separated Comment", passed, total); + RunSpecTest(&Spec::CommentLines, "6.10", "Comment Lines", passed, total); + RunSpecTest(&Spec::SeparationSpacesII, "6.11", "Separation Spaces", passed, total); + + RunSpecTest(&Spec::NodeAnchors, "6.29", "Node Anchors", passed, total); + + RunSpecTest(&Spec::AliasNodes, "7.1", "Alias Nodes", passed, total); + RunSpecTest(&Spec::EmptyNodes, "7.2", "Empty Nodes", passed, total); + RunSpecTest(&Spec::CompletelyEmptyNodes, "7.3", "Completely Empty Nodes", passed, total); + RunSpecTest(&Spec::DoubleQuotedImplicitKeys, "7.4", "Double Quoted Implicit Keys", passed, total); + RunSpecTest(&Spec::DoubleQuotedLineBreaks, "7.5", "Double Quoted Line Breaks", passed, total); + RunSpecTest(&Spec::DoubleQuotedLines, "7.6", "Double Quoted Lines", passed, total); + RunSpecTest(&Spec::SingleQuotedCharacters, "7.7", "Single Quoted Characters", passed, total); + RunSpecTest(&Spec::SingleQuotedImplicitKeys, "7.8", "Single Quoted Implicit Keys", passed, total); + RunSpecTest(&Spec::SingleQuotedLines, "7.9", "Single Quoted Lines", passed, total); + RunSpecTest(&Spec::PlainCharacters, "7.10", "Plain Characters", passed, total); + RunSpecTest(&Spec::PlainImplicitKeys, "7.11", "Plain Implicit Keys", passed, total); + RunSpecTest(&Spec::PlainLines, "7.12", "Plain Lines", passed, total); + + std::cout << "Spec tests: " << passed << "/" << total << " passed\n"; + return passed == total; + } + +} + diff --git a/yaml-reader/spectests.h b/yaml-reader/spectests.h new file mode 100644 index 0000000..fcb1fb4 --- /dev/null +++ b/yaml-reader/spectests.h @@ -0,0 +1,11 @@ +#pragma once + +#ifndef SPECTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define SPECTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +namespace Test { + bool RunSpecTests(); +} + +#endif // SPECTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp new file mode 100644 index 0000000..492a5d1 --- /dev/null +++ b/yaml-reader/tests.cpp @@ -0,0 +1,29 @@ +#include "tests.h" +#include "emittertests.h" +#include "parsertests.h" +#include "spectests.h" +#include "yaml.h" +#include +#include +#include +#include + +namespace Test +{ + void RunAll() + { + bool passed = true; + if(!RunParserTests()) + passed = false; + + if(!RunEmitterTests()) + passed = false; + + if(!RunSpecTests()) + passed = false; + + if(passed) + std::cout << "All tests passed!\n"; + } +} + diff --git a/yaml-reader/tests.h b/yaml-reader/tests.h new file mode 100644 index 0000000..0d39007 --- /dev/null +++ b/yaml-reader/tests.h @@ -0,0 +1,51 @@ +#pragma once + +#ifndef TESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define TESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#include + +namespace Test { + void RunAll(); + + namespace Parser { + // scalar tests + void SimpleScalar(std::string& inputScalar, std::string& desiredOutput); + void MultiLineScalar(std::string& inputScalar, std::string& desiredOutput); + void LiteralScalar(std::string& inputScalar, std::string& desiredOutput); + void FoldedScalar(std::string& inputScalar, std::string& desiredOutput); + void ChompedFoldedScalar(std::string& inputScalar, std::string& desiredOutput); + void ChompedLiteralScalar(std::string& inputScalar, std::string& desiredOutput); + void FoldedScalarWithIndent(std::string& inputScalar, std::string& desiredOutput); + void ColonScalar(std::string& inputScalar, std::string& desiredOutput); + void QuotedScalar(std::string& inputScalar, std::string& desiredOutput); + void CommaScalar(std::string& inputScalar, std::string& desiredOutput); + void DashScalar(std::string& inputScalar, std::string& desiredOutput); + void URLScalar(std::string& inputScalar, std::string& desiredOutput); + + // misc tests + bool SimpleSeq(); + bool SimpleMap(); + bool FlowSeq(); + bool FlowMap(); + bool FlowMapWithOmittedKey(); + bool FlowMapWithOmittedValue(); + bool FlowMapWithSoloEntry(); + bool FlowMapEndingWithSoloEntry(); + bool QuotedSimpleKeys(); + bool CompressedMapAndSeq(); + bool NullBlockSeqEntry(); + bool NullBlockMapKey(); + bool NullBlockMapValue(); + bool SimpleAlias(); + bool AliasWithNull(); + bool AnchorInSimpleKey(); + bool AliasAsSimpleKey(); + bool ExplicitDoc(); + bool MultipleDocs(); + bool ExplicitEndDoc(); + bool MultipleDocsWithSomeExplicitIndicators(); + } +} + +#endif // TESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-reader/tests/aliased.yaml b/yaml-reader/tests/aliased.yaml new file mode 100644 index 0000000..ca79a64 --- /dev/null +++ b/yaml-reader/tests/aliased.yaml @@ -0,0 +1,4 @@ +--- &list +- This document contains a recursive list. +- *list +... From 5986307b8e88b18a60a878bf551fd82eea5e272b Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 27 Oct 2009 14:47:08 +0000 Subject: [PATCH 193/295] Now actually removed yaml-reader --- CMakeLists.txt | 4 +- yaml-reader/CMakeLists.txt | 10 - yaml-reader/emittertests.cpp | 650 ---------------- yaml-reader/emittertests.h | 11 - yaml-reader/main.cpp | 11 - yaml-reader/parsertests.cpp | 888 ---------------------- yaml-reader/parsertests.h | 11 - yaml-reader/spectests.cpp | 1280 -------------------------------- yaml-reader/spectests.h | 11 - yaml-reader/tests.cpp | 29 - yaml-reader/tests.h | 51 -- yaml-reader/tests/aliased.yaml | 4 - 12 files changed, 2 insertions(+), 2958 deletions(-) delete mode 100644 yaml-reader/CMakeLists.txt delete mode 100644 yaml-reader/emittertests.cpp delete mode 100644 yaml-reader/emittertests.h delete mode 100644 yaml-reader/main.cpp delete mode 100644 yaml-reader/parsertests.cpp delete mode 100644 yaml-reader/parsertests.h delete mode 100644 yaml-reader/spectests.cpp delete mode 100644 yaml-reader/spectests.h delete mode 100644 yaml-reader/tests.cpp delete mode 100644 yaml-reader/tests.h delete mode 100644 yaml-reader/tests/aliased.yaml diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e061e0..4ab7746 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML enable_testing() -option(YAML_CPP_BUILD_TOOLS "Enables or disables yaml-reader and parse tools" true) +option(YAML_CPP_BUILD_TOOLS "Enables or disables testing and parse tools" true) if(WIN32) set(_library_dir bin) # .dll are in PATH, like executables @@ -67,6 +67,6 @@ if(UNIX) endif(UNIX) if(YAML_CPP_BUILD_TOOLS) - add_subdirectory (yaml-reader) + add_subdirectory (test) add_subdirectory (util) endif(YAML_CPP_BUILD_TOOLS) diff --git a/yaml-reader/CMakeLists.txt b/yaml-reader/CMakeLists.txt deleted file mode 100644 index 2b58180..0000000 --- a/yaml-reader/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -file(GLOB yaml-reader_headers [a-z]*.h) -file(GLOB yaml-reader_sources [a-z]*.cpp) - -add_executable(yaml-reader - ${yaml-reader_sources} - ${yaml-reader_headers} -) -target_link_libraries(yaml-reader yaml-cpp) - -add_test(yaml-reader-test yaml-reader) diff --git a/yaml-reader/emittertests.cpp b/yaml-reader/emittertests.cpp deleted file mode 100644 index f85af8d..0000000 --- a/yaml-reader/emittertests.cpp +++ /dev/null @@ -1,650 +0,0 @@ -#include "tests.h" -#include "yaml.h" - -namespace Test -{ - namespace Emitter { - //////////////////////////////////////////////////////////////////////////////////////////////////////// - // correct emitting - - void SimpleScalar(YAML::Emitter& out, std::string& desiredOutput) { - out << "Hello, World!"; - desiredOutput = "Hello, World!"; - } - - void SimpleSeq(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginSeq; - out << "eggs"; - out << "bread"; - out << "milk"; - out << YAML::EndSeq; - - desiredOutput = "- eggs\n- bread\n- milk"; - } - - void SimpleFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::Flow; - out << YAML::BeginSeq; - out << "Larry"; - out << "Curly"; - out << "Moe"; - out << YAML::EndSeq; - - desiredOutput = "[Larry, Curly, Moe]"; - } - - void EmptyFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::Flow; - out << YAML::BeginSeq; - out << YAML::EndSeq; - - desiredOutput = "[]"; - } - - void NestedBlockSeq(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginSeq; - out << "item 1"; - out << YAML::BeginSeq << "subitem 1" << "subitem 2" << YAML::EndSeq; - out << YAML::EndSeq; - - desiredOutput = "- item 1\n-\n - subitem 1\n - subitem 2"; - } - - void NestedFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginSeq; - out << "one"; - out << YAML::Flow << YAML::BeginSeq << "two" << "three" << YAML::EndSeq; - out << YAML::EndSeq; - - desiredOutput = "- one\n- [two, three]"; - } - - void SimpleMap(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginMap; - out << YAML::Key << "name"; - out << YAML::Value << "Ryan Braun"; - out << YAML::Key << "position"; - out << YAML::Value << "3B"; - out << YAML::EndMap; - - desiredOutput = "name: Ryan Braun\nposition: 3B"; - } - - void SimpleFlowMap(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::Flow; - out << YAML::BeginMap; - out << YAML::Key << "shape"; - out << YAML::Value << "square"; - out << YAML::Key << "color"; - out << YAML::Value << "blue"; - out << YAML::EndMap; - - desiredOutput = "{shape: square, color: blue}"; - } - - void MapAndList(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginMap; - out << YAML::Key << "name"; - out << YAML::Value << "Barack Obama"; - out << YAML::Key << "children"; - out << YAML::Value << YAML::BeginSeq << "Sasha" << "Malia" << YAML::EndSeq; - out << YAML::EndMap; - - desiredOutput = "name: Barack Obama\nchildren:\n - Sasha\n - Malia"; - } - - void ListAndMap(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginSeq; - out << "item 1"; - out << YAML::BeginMap; - out << YAML::Key << "pens" << YAML::Value << 8; - out << YAML::Key << "pencils" << YAML::Value << 14; - out << YAML::EndMap; - out << "item 2"; - out << YAML::EndSeq; - - desiredOutput = "- item 1\n-\n pens: 8\n pencils: 14\n- item 2"; - } - - void NestedBlockMap(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginMap; - out << YAML::Key << "name"; - out << YAML::Value << "Fred"; - out << YAML::Key << "grades"; - out << YAML::Value; - out << YAML::BeginMap; - out << YAML::Key << "algebra" << YAML::Value << "A"; - out << YAML::Key << "physics" << YAML::Value << "C+"; - out << YAML::Key << "literature" << YAML::Value << "B"; - out << YAML::EndMap; - out << YAML::EndMap; - - desiredOutput = "name: Fred\ngrades:\n algebra: A\n physics: C+\n literature: B"; - } - - void NestedFlowMap(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::Flow; - out << YAML::BeginMap; - out << YAML::Key << "name"; - out << YAML::Value << "Fred"; - out << YAML::Key << "grades"; - out << YAML::Value; - out << YAML::BeginMap; - out << YAML::Key << "algebra" << YAML::Value << "A"; - out << YAML::Key << "physics" << YAML::Value << "C+"; - out << YAML::Key << "literature" << YAML::Value << "B"; - out << YAML::EndMap; - out << YAML::EndMap; - - desiredOutput = "{name: Fred, grades: {algebra: A, physics: C+, literature: B}}"; - } - - void MapListMix(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::BeginMap; - out << YAML::Key << "name"; - out << YAML::Value << "Bob"; - out << YAML::Key << "position"; - out << YAML::Value; - out << YAML::Flow << YAML::BeginSeq << 2 << 4 << YAML::EndSeq; - out << YAML::Key << "invincible" << YAML::Value << YAML::OnOffBool << false; - out << YAML::EndMap; - - desiredOutput = "name: Bob\nposition: [2, 4]\ninvincible: off"; - } - - void SimpleLongKey(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::LongKey; - out << YAML::BeginMap; - out << YAML::Key << "height"; - out << YAML::Value << "5'9\""; - out << YAML::Key << "weight"; - out << YAML::Value << 145; - out << YAML::EndMap; - - desiredOutput = "? height\n: 5'9\"\n? weight\n: 145"; - } - - void SingleLongKey(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::Key << "age"; - out << YAML::Value << "24"; - out << YAML::LongKey << YAML::Key << "height"; - out << YAML::Value << "5'9\""; - out << YAML::Key << "weight"; - out << YAML::Value << 145; - out << YAML::EndMap; - - desiredOutput = "age: 24\n? height\n: 5'9\"\nweight: 145"; - } - - void ComplexLongKey(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::LongKey; - out << YAML::BeginMap; - out << YAML::Key << YAML::BeginSeq << 1 << 3 << YAML::EndSeq; - out << YAML::Value << "monster"; - out << YAML::Key << YAML::Flow << YAML::BeginSeq << 2 << 0 << YAML::EndSeq; - out << YAML::Value << "demon"; - out << YAML::EndMap; - - desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon"; - } - - void AutoLongKey(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::Key << YAML::BeginSeq << 1 << 3 << YAML::EndSeq; - out << YAML::Value << "monster"; - out << YAML::Key << YAML::Flow << YAML::BeginSeq << 2 << 0 << YAML::EndSeq; - out << YAML::Value << "demon"; - out << YAML::Key << "the origin"; - out << YAML::Value << "angel"; - out << YAML::EndMap; - - desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon\nthe origin: angel"; - } - - void ScalarFormat(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginSeq; - out << "simple scalar"; - out << YAML::SingleQuoted << "explicit single-quoted scalar"; - out << YAML::DoubleQuoted << "explicit double-quoted scalar"; - out << "auto-detected\ndouble-quoted scalar"; - out << "a non-\"auto-detected\" double-quoted scalar"; - out << YAML::Literal << "literal scalar\nthat may span\nmany, many\nlines and have \"whatever\" crazy\tsymbols that we like"; - out << YAML::EndSeq; - - desiredOutput = "- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\x0adouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like"; - } - - void AutoLongKeyScalar(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::Key << YAML::Literal << "multi-line\nscalar"; - out << YAML::Value << "and its value"; - out << YAML::EndMap; - - desiredOutput = "? |\n multi-line\n scalar\n: and its value"; - } - - void LongKeyFlowMap(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::Flow; - out << YAML::BeginMap; - out << YAML::Key << "simple key"; - out << YAML::Value << "and value"; - out << YAML::LongKey << YAML::Key << "long key"; - out << YAML::Value << "and its value"; - out << YAML::EndMap; - - desiredOutput = "{simple key: and value, ? long key: and its value}"; - } - - void BlockMapAsKey(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::Key; - out << YAML::BeginMap; - out << YAML::Key << "key" << YAML::Value << "value"; - out << YAML::Key << "next key" << YAML::Value << "next value"; - out << YAML::EndMap; - out << YAML::Value; - out << "total value"; - out << YAML::EndMap; - - desiredOutput = "?\n key: value\n next key: next value\n: total value"; - } - - void AliasAndAnchor(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginSeq; - out << YAML::Anchor("fred"); - out << YAML::BeginMap; - out << YAML::Key << "name" << YAML::Value << "Fred"; - out << YAML::Key << "age" << YAML::Value << 42; - out << YAML::EndMap; - out << YAML::Alias("fred"); - out << YAML::EndSeq; - - desiredOutput = "- &fred\n name: Fred\n age: 42\n- *fred"; - } - - void AliasAndAnchorWithNull(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginSeq; - out << YAML::Anchor("fred") << YAML::Null; - out << YAML::Alias("fred"); - out << YAML::EndSeq; - - desiredOutput = "- &fred ~\n- *fred"; - } - - void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::Key << "receipt"; - out << YAML::Value << "Oz-Ware Purchase Invoice"; - out << YAML::Key << "date"; - out << YAML::Value << "2007-08-06"; - out << YAML::Key << "customer"; - out << YAML::Value; - out << YAML::BeginMap; - out << YAML::Key << "given"; - out << YAML::Value << "Dorothy"; - out << YAML::Key << "family"; - out << YAML::Value << "Gale"; - out << YAML::EndMap; - out << YAML::Key << "items"; - out << YAML::Value; - out << YAML::BeginSeq; - out << YAML::BeginMap; - out << YAML::Key << "part_no"; - out << YAML::Value << "A4786"; - out << YAML::Key << "descrip"; - out << YAML::Value << "Water Bucket (Filled)"; - out << YAML::Key << "price"; - out << YAML::Value << 1.47; - out << YAML::Key << "quantity"; - out << YAML::Value << 4; - out << YAML::EndMap; - out << YAML::BeginMap; - out << YAML::Key << "part_no"; - out << YAML::Value << "E1628"; - out << YAML::Key << "descrip"; - out << YAML::Value << "High Heeled \"Ruby\" Slippers"; - out << YAML::Key << "price"; - out << YAML::Value << 100.27; - out << YAML::Key << "quantity"; - out << YAML::Value << 1; - out << YAML::EndMap; - out << YAML::EndSeq; - out << YAML::Key << "bill-to"; - out << YAML::Value << YAML::Anchor("id001"); - out << YAML::BeginMap; - out << YAML::Key << "street"; - out << YAML::Value << YAML::Literal << "123 Tornado Alley\nSuite 16"; - out << YAML::Key << "city"; - out << YAML::Value << "East Westville"; - out << YAML::Key << "state"; - out << YAML::Value << "KS"; - out << YAML::EndMap; - out << YAML::Key << "ship-to"; - out << YAML::Value << YAML::Alias("id001"); - out << YAML::EndMap; - - desiredOutput = "receipt: Oz-Ware Purchase Invoice\ndate: 2007-08-06\ncustomer:\n given: Dorothy\n family: Gale\nitems:\n -\n part_no: A4786\n descrip: Water Bucket (Filled)\n price: 1.47\n quantity: 4\n -\n part_no: E1628\n descrip: High Heeled \"Ruby\" Slippers\n price: 100.27\n quantity: 1\nbill-to: &id001\n street: |\n 123 Tornado Alley\n Suite 16\n city: East Westville\n state: KS\nship-to: *id001"; - } - - void STLContainers(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginSeq; - std::vector primes; - primes.push_back(2); - primes.push_back(3); - primes.push_back(5); - primes.push_back(7); - primes.push_back(11); - primes.push_back(13); - out << YAML::Flow << primes; - std::map ages; - ages["Daniel"] = 26; - ages["Jesse"] = 24; - out << ages; - out << YAML::EndSeq; - - desiredOutput = "- [2, 3, 5, 7, 11, 13]\n-\n Daniel: 26\n Jesse: 24"; - } - - void SimpleComment(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::Key << "method"; - out << YAML::Value << "least squares" << YAML::Comment("should we change this method?"); - out << YAML::EndMap; - - desiredOutput = "method: least squares # should we change this method?"; - } - - void MultiLineComment(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginSeq; - out << "item 1" << YAML::Comment("really really long\ncomment that couldn't possibly\nfit on one line"); - out << "item 2"; - out << YAML::EndSeq; - - desiredOutput = "- item 1 # really really long\n # comment that couldn't possibly\n # fit on one line\n- item 2"; - } - - void ComplexComments(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginMap; - out << YAML::LongKey << YAML::Key << "long key" << YAML::Comment("long key"); - out << YAML::Value << "value"; - out << YAML::EndMap; - - desiredOutput = "? long key # long key\n: value"; - } - - void Indentation(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::Indent(4); - out << YAML::BeginSeq; - out << YAML::BeginMap; - out << YAML::Key << "key 1" << YAML::Value << "value 1"; - out << YAML::Key << "key 2" << YAML::Value << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; - out << YAML::EndMap; - out << YAML::EndSeq; - - desiredOutput = "-\n key 1: value 1\n key 2:\n - a\n - b\n - c"; - } - - void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) - { - out.SetIndent(4); - out.SetMapFormat(YAML::LongKey); - - out << YAML::BeginSeq; - out << YAML::BeginMap; - out << YAML::Key << "key 1" << YAML::Value << "value 1"; - out << YAML::Key << "key 2" << YAML::Value << YAML::Flow << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; - out << YAML::EndMap; - out << YAML::EndSeq; - - desiredOutput = "-\n ? key 1\n : value 1\n ? key 2\n : [a, b, c]"; - } - - void ComplexGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginSeq; - out << YAML::Block; - out << YAML::BeginMap; - out << YAML::Key << "key 1" << YAML::Value << "value 1"; - out << YAML::Key << "key 2" << YAML::Value; - out.SetSeqFormat(YAML::Flow); - out << YAML::BeginSeq << "a" << "b" << "c" << YAML::EndSeq; - out << YAML::EndMap; - out << YAML::BeginMap; - out << YAML::Key << YAML::BeginSeq << 1 << 2 << YAML::EndSeq; - out << YAML::Value << YAML::BeginMap << YAML::Key << "a" << YAML::Value << "b" << YAML::EndMap; - out << YAML::EndMap; - out << YAML::EndSeq; - - desiredOutput = "-\n key 1: value 1\n key 2: [a, b, c]\n-\n ? [1, 2]\n :\n a: b"; - } - - void Null(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::BeginSeq; - out << YAML::Null; - out << YAML::BeginMap; - out << YAML::Key << "null value" << YAML::Value << YAML::Null; - out << YAML::Key << YAML::Null << YAML::Value << "null key"; - out << YAML::EndMap; - out << YAML::EndSeq; - - desiredOutput = "- ~\n-\n null value: ~\n ~: null key"; - } - - void EscapedUnicode(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::EscapeNonAscii << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; - - desiredOutput = "\"$ \\xa2 \\u20ac \\U00024b62\""; - } - - void Unicode(YAML::Emitter& out, std::string& desiredOutput) - { - out << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; - desiredOutput = "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; - } - - void DoubleQuotedUnicode(YAML::Emitter& out, std::string& desiredOutput) - { - out << YAML::DoubleQuoted << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; - desiredOutput = "\"\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2\""; - } - - - //////////////////////////////////////////////////////////////////////////////////////////////////////// - // incorrect emitting - - void ExtraEndSeq(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::UNEXPECTED_END_SEQ; - - out << YAML::BeginSeq; - out << "Hello"; - out << "World"; - out << YAML::EndSeq; - out << YAML::EndSeq; - } - - void ExtraEndMap(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::UNEXPECTED_END_MAP; - - out << YAML::BeginMap; - out << YAML::Key << "Hello" << YAML::Value << "World"; - out << YAML::EndMap; - out << YAML::EndMap; - } - - void BadSingleQuoted(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::SINGLE_QUOTED_CHAR; - - out << YAML::SingleQuoted << "Hello\nWorld"; - } - - void InvalidAnchor(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::INVALID_ANCHOR; - - out << YAML::BeginSeq; - out << YAML::Anchor("new\nline") << "Test"; - out << YAML::EndSeq; - } - - void InvalidAlias(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::INVALID_ALIAS; - - out << YAML::BeginSeq; - out << YAML::Alias("new\nline"); - out << YAML::EndSeq; - } - - void MissingKey(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::EXPECTED_KEY_TOKEN; - - out << YAML::BeginMap; - out << YAML::Key << "key" << YAML::Value << "value"; - out << "missing key" << YAML::Value << "value"; - out << YAML::EndMap; - } - - void MissingValue(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::EXPECTED_VALUE_TOKEN; - - out << YAML::BeginMap; - out << YAML::Key << "key" << "value"; - out << YAML::EndMap; - } - - void UnexpectedKey(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::UNEXPECTED_KEY_TOKEN; - - out << YAML::BeginSeq; - out << YAML::Key << "hi"; - out << YAML::EndSeq; - } - - void UnexpectedValue(YAML::Emitter& out, std::string& desiredError) - { - desiredError = YAML::ErrorMsg::UNEXPECTED_VALUE_TOKEN; - - out << YAML::BeginSeq; - out << YAML::Value << "hi"; - out << YAML::EndSeq; - } - } - - namespace { - void RunEmitterTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, int& passed, int& total) { - YAML::Emitter out; - std::string desiredOutput; - test(out, desiredOutput); - std::string output = out.c_str(); - - if(output == desiredOutput) { - passed++; - } else { - std::cout << "Emitter test failed: " << name << "\n"; - std::cout << "Output:\n"; - std::cout << output << "<<<\n"; - std::cout << "Desired output:\n"; - std::cout << desiredOutput << "<<<\n"; - } - total++; - } - - void RunEmitterErrorTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, int& passed, int& total) { - YAML::Emitter out; - std::string desiredError; - test(out, desiredError); - std::string lastError = out.GetLastError(); - if(!out.good() && lastError == desiredError) { - passed++; - } else { - std::cout << "Emitter test failed: " << name << "\n"; - if(out.good()) - std::cout << "No error detected\n"; - else - std::cout << "Detected error: " << lastError << "\n"; - std::cout << "Expected error: " << desiredError << "\n"; - } - total++; - } - } - - bool RunEmitterTests() - { - int passed = 0; - int total = 0; - RunEmitterTest(&Emitter::SimpleScalar, "simple scalar", passed, total); - RunEmitterTest(&Emitter::SimpleSeq, "simple seq", passed, total); - RunEmitterTest(&Emitter::SimpleFlowSeq, "simple flow seq", passed, total); - RunEmitterTest(&Emitter::EmptyFlowSeq, "empty flow seq", passed, total); - RunEmitterTest(&Emitter::NestedBlockSeq, "nested block seq", passed, total); - RunEmitterTest(&Emitter::NestedFlowSeq, "nested flow seq", passed, total); - RunEmitterTest(&Emitter::SimpleMap, "simple map", passed, total); - RunEmitterTest(&Emitter::SimpleFlowMap, "simple flow map", passed, total); - RunEmitterTest(&Emitter::MapAndList, "map and list", passed, total); - RunEmitterTest(&Emitter::ListAndMap, "list and map", passed, total); - RunEmitterTest(&Emitter::NestedBlockMap, "nested block map", passed, total); - RunEmitterTest(&Emitter::NestedFlowMap, "nested flow map", passed, total); - RunEmitterTest(&Emitter::MapListMix, "map list mix", passed, total); - RunEmitterTest(&Emitter::SimpleLongKey, "simple long key", passed, total); - RunEmitterTest(&Emitter::SingleLongKey, "single long key", passed, total); - RunEmitterTest(&Emitter::ComplexLongKey, "complex long key", passed, total); - RunEmitterTest(&Emitter::AutoLongKey, "auto long key", passed, total); - RunEmitterTest(&Emitter::ScalarFormat, "scalar format", passed, total); - RunEmitterTest(&Emitter::AutoLongKeyScalar, "auto long key scalar", passed, total); - RunEmitterTest(&Emitter::LongKeyFlowMap, "long key flow map", passed, total); - RunEmitterTest(&Emitter::BlockMapAsKey, "block map as key", passed, total); - RunEmitterTest(&Emitter::AliasAndAnchor, "alias and anchor", passed, total); - RunEmitterTest(&Emitter::AliasAndAnchorWithNull, "alias and anchor with null", passed, total); - RunEmitterTest(&Emitter::ComplexDoc, "complex doc", passed, total); - RunEmitterTest(&Emitter::STLContainers, "STL containers", passed, total); - RunEmitterTest(&Emitter::SimpleComment, "simple comment", passed, total); - RunEmitterTest(&Emitter::MultiLineComment, "multi-line comment", passed, total); - RunEmitterTest(&Emitter::ComplexComments, "complex comments", passed, total); - RunEmitterTest(&Emitter::Indentation, "indentation", passed, total); - RunEmitterTest(&Emitter::SimpleGlobalSettings, "simple global settings", passed, total); - RunEmitterTest(&Emitter::ComplexGlobalSettings, "complex global settings", passed, total); - RunEmitterTest(&Emitter::Null, "null", passed, total); - RunEmitterTest(&Emitter::EscapedUnicode, "escaped unicode", passed, total); - RunEmitterTest(&Emitter::Unicode, "unicode", passed, total); - RunEmitterTest(&Emitter::DoubleQuotedUnicode, "double quoted unicode", passed, total); - - RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total); - RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total); - RunEmitterErrorTest(&Emitter::BadSingleQuoted, "bad single quoted string", passed, total); - RunEmitterErrorTest(&Emitter::InvalidAnchor, "invalid anchor", passed, total); - RunEmitterErrorTest(&Emitter::InvalidAlias, "invalid alias", passed, total); - RunEmitterErrorTest(&Emitter::MissingKey, "missing key", passed, total); - RunEmitterErrorTest(&Emitter::MissingValue, "missing value", passed, total); - RunEmitterErrorTest(&Emitter::UnexpectedKey, "unexpected key", passed, total); - RunEmitterErrorTest(&Emitter::UnexpectedValue, "unexpected value", passed, total); - - std::cout << "Emitter tests: " << passed << "/" << total << " passed\n"; - return passed == total; - } -} - diff --git a/yaml-reader/emittertests.h b/yaml-reader/emittertests.h deleted file mode 100644 index e746e5a..0000000 --- a/yaml-reader/emittertests.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#ifndef EMITTERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#define EMITTERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 - -namespace Test { - bool RunEmitterTests(); -} - -#endif // EMITTERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 - diff --git a/yaml-reader/main.cpp b/yaml-reader/main.cpp deleted file mode 100644 index 881bc57..0000000 --- a/yaml-reader/main.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "tests.h" - -int main() -{ -#ifdef WINDOWS - _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF); -#endif // WINDOWS - Test::RunAll(); - - return 0; -} diff --git a/yaml-reader/parsertests.cpp b/yaml-reader/parsertests.cpp deleted file mode 100644 index 138143c..0000000 --- a/yaml-reader/parsertests.cpp +++ /dev/null @@ -1,888 +0,0 @@ -#include "tests.h" -#include "yaml.h" -#include -#include - -namespace Test -{ - namespace Parser { - void SimpleScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = "Hello, World!"; - desiredOutput = "Hello, World!"; - } - - void MultiLineScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = - "normal scalar, but\n" - "over several lines"; - desiredOutput = "normal scalar, but over several lines"; - } - - void LiteralScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = - "|\n" - " literal scalar - so we can draw ASCII:\n" - " \n" - " - -\n" - " | - |\n" - " -----\n"; - desiredOutput = - "literal scalar - so we can draw ASCII:\n" - "\n" - " - -\n" - " | - |\n" - " -----\n"; - } - - void FoldedScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = - ">\n" - " and a folded scalar... so we\n" - " can just keep writing various\n" - " things. And if we want to keep indentation:\n" - " \n" - " we just indent a little\n" - " see, this stays indented"; - desiredOutput = - "and a folded scalar... so we" - " can just keep writing various" - " things. And if we want to keep indentation:\n" - "\n" - " we just indent a little\n" - " see, this stays indented"; - } - - void ChompedFoldedScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = - ">-\n" - " Here's a folded scalar\n" - " that gets chomped."; - desiredOutput = - "Here's a folded scalar" - " that gets chomped."; - } - - void ChompedLiteralScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = - "|-\n" - " Here's a literal scalar\n" - " that gets chomped."; - desiredOutput = - "Here's a literal scalar\n" - "that gets chomped."; - } - - void FoldedScalarWithIndent(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = - ">2\n" - " Here's a folded scalar\n" - " that starts with some indentation."; - desiredOutput = - " Here's a folded scalar\n" - "that starts with some indentation."; - } - - void ColonScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = "::vector"; - desiredOutput = "::vector"; - } - - void QuotedScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = "\": - ()\""; - desiredOutput = ": - ()"; - } - - void CommaScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = "Up, up, and away!"; - desiredOutput = "Up, up, and away!"; - } - - void DashScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = "-123"; - desiredOutput = "-123"; - } - - void URLScalar(std::string& inputScalar, std::string& desiredOutput) - { - inputScalar = "http://example.com/foo#bar"; - desiredOutput = "http://example.com/foo#bar"; - } - - bool SimpleSeq() - { - std::string input = - "- eggs\n" - "- bread\n" - "- milk"; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - std::string output; - doc[0] >> output; - if(output != "eggs") - return false; - doc[1] >> output; - if(output != "bread") - return false; - doc[2] >> output; - if(output != "milk") - return false; - - return true; - } - - bool SimpleMap() - { - std::string input = - "name: Prince Fielder\n" - "position: 1B\n" - "bats: L"; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - std::string output; - doc["name"] >> output; - if(output != "Prince Fielder") - return false; - doc["position"] >> output; - if(output != "1B") - return false; - doc["bats"] >> output; - if(output != "L") - return false; - - return true; - } - - bool FlowSeq() - { - std::string input = "[ 2 , 3, 5 , 7, 11]"; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - int output; - doc[0] >> output; - if(output != 2) - return false; - doc[1] >> output; - if(output != 3) - return false; - doc[2] >> output; - if(output != 5) - return false; - doc[3] >> output; - if(output != 7) - return false; - doc[4] >> output; - if(output != 11) - return false; - - return true; - } - - bool FlowMap() - { - std::string input = "{hr: 65, avg: 0.278}"; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - std::string output; - doc["hr"] >> output; - if(output != "65") - return false; - doc["avg"] >> output; - if(output != "0.278") - return false; - - return true; - } - - bool FlowMapWithOmittedKey() - { - std::string input = "{: omitted key}"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - std::string output; - doc[YAML::Null] >> output; - if(output != "omitted key") - return false; - - return true; - } - - bool FlowMapWithOmittedValue() - { - std::string input = "{a: b, c:, d:}"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - std::string output; - doc["a"] >> output; - if(output != "b") - return false; - if(!IsNull(doc["c"])) - return false; - if(!IsNull(doc["d"])) - return false; - - return true; - } - - bool FlowMapWithSoloEntry() - { - std::string input = "{a: b, c, d: e}"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - std::string output; - doc["a"] >> output; - if(output != "b") - return false; - if(!IsNull(doc["c"])) - return false; - doc["d"] >> output; - if(output != "e") - return false; - - return true; - } - - bool FlowMapEndingWithSoloEntry() - { - std::string input = "{a: b, c}"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - std::string output; - doc["a"] >> output; - if(output != "b") - return false; - if(!IsNull(doc["c"])) - return false; - - return true; - } - - bool QuotedSimpleKeys() - { - std::string KeyValue[3] = { "\"double\": double\n", "'single': single\n", "plain: plain\n" }; - - int perm[3] = { 0, 1, 2 }; - do { - std::string input = KeyValue[perm[0]] + KeyValue[perm[1]] + KeyValue[perm[2]]; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - std::string output; - doc["double"] >> output; - if(output != "double") - return false; - doc["single"] >> output; - if(output != "single") - return false; - doc["plain"] >> output; - if(output != "plain") - return false; - } while(std::next_permutation(perm, perm + 3)); - - return true; - } - - bool CompressedMapAndSeq() - { - std::string input = "key:\n- one\n- two"; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - const YAML::Node& seq = doc["key"]; - if(seq.size() != 2) - return false; - - std::string output; - seq[0] >> output; - if(output != "one") - return false; - seq[1] >> output; - if(output != "two") - return false; - - return true; - } - - bool NullBlockSeqEntry() - { - std::string input = "- hello\n-\n- world"; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - std::string output; - doc[0] >> output; - if(output != "hello") - return false; - if(!IsNull(doc[1])) - return false; - doc[2] >> output; - if(output != "world") - return false; - - return true; - } - - bool NullBlockMapKey() - { - std::string input = ": empty key"; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - std::string output; - doc[YAML::Null] >> output; - if(output != "empty key") - return false; - - return true; - } - - bool NullBlockMapValue() - { - std::string input = "empty value:"; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - if(!IsNull(doc["empty value"])) - return false; - - return true; - } - - bool SimpleAlias() - { - std::string input = "- &alias test\n- *alias"; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - std::string output; - doc[0] >> output; - if(output != "test") - return false; - - doc[1] >> output; - if(output != "test") - return false; - - if(doc.size() != 2) - return false; - - return true; - } - - bool AliasWithNull() - { - std::string input = "- &alias\n- *alias"; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - if(!IsNull(doc[0])) - return false; - - if(!IsNull(doc[1])) - return false; - - if(doc.size() != 2) - return false; - - return true; - } - - bool AnchorInSimpleKey() - { - std::string input = "- &a b: c\n- *a"; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - if(doc.size() != 2) - return false; - - std::string output; - doc[0]["b"] >> output; - if(output != "c") - return false; - - doc[1] >> output; - if(output != "b") - return false; - - return true; - } - - bool AliasAsSimpleKey() - { - std::string input = "- &a b\n- *a: c"; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - if(doc.size() != 2) - return false; - - std::string output; - doc[0] >> output; - if(output != "b") - return false; - - doc[1]["b"] >> output; - if(output != "c") - return false; - - return true; - } - - bool ExplicitDoc() - { - std::string input = "---\n- one\n- two"; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - if(doc.size() != 2) - return false; - - std::string output; - doc[0] >> output; - if(output != "one") - return false; - doc[1] >> output; - if(output != "two") - return false; - - return true; - } - - bool MultipleDocs() - { - std::string input = "---\nname: doc1\n---\nname: doc2"; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - std::string output; - doc["name"] >> output; - if(output != "doc1") - return false; - - if(!parser) - return false; - - parser.GetNextDocument(doc); - doc["name"] >> output; - if(output != "doc2") - return false; - - return true; - } - - bool ExplicitEndDoc() - { - std::string input = "- one\n- two\n...\n..."; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - - if(doc.size() != 2) - return false; - - std::string output; - doc[0] >> output; - if(output != "one") - return false; - doc[1] >> output; - if(output != "two") - return false; - - return true; - } - - bool MultipleDocsWithSomeExplicitIndicators() - { - std::string input = - "- one\n- two\n...\n" - "---\nkey: value\n...\n...\n" - "- three\n- four\n" - "---\nkey: value"; - - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML::Node doc; - std::string output; - - parser.GetNextDocument(doc); - if(doc.size() != 2) - return false; - doc[0] >> output; - if(output != "one") - return false; - doc[1] >> output; - if(output != "two") - return false; - - parser.GetNextDocument(doc); - doc["key"] >> output; - if(output != "value") - return false; - - parser.GetNextDocument(doc); - if(doc.size() != 2) - return false; - doc[0] >> output; - if(output != "three") - return false; - doc[1] >> output; - if(output != "four") - return false; - - parser.GetNextDocument(doc); - doc["key"] >> output; - if(output != "value") - return false; - - return true; - } - } - - namespace { - void RunScalarParserTest(void (*test)(std::string&, std::string&), const std::string& name, int& passed, int& total) { - std::string error; - std::string inputScalar, desiredOutput; - std::string output; - bool ok = true; - try { - test(inputScalar, desiredOutput); - std::stringstream stream(inputScalar); - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - doc >> output; - } catch(const YAML::Exception& e) { - ok = false; - error = e.msg; - } - if(ok && output == desiredOutput) { - passed++; - } else { - std::cout << "Parser test failed: " << name << "\n"; - if(error != "") - std::cout << "Caught exception: " << error << "\n"; - else { - std::cout << "Output:\n" << output << "<<<\n"; - std::cout << "Desired output:\n" << desiredOutput << "<<<\n"; - } - } - total++; - } - - void RunParserTest(bool (*test)(), const std::string& name, int& passed, int& total) { - std::string error; - bool ok = true; - try { - ok = test(); - } catch(const YAML::Exception& e) { - ok = false; - error = e.msg; - } - if(ok) { - passed++; - } else { - std::cout << "Parser test failed: " << name << "\n"; - if(error != "") - std::cout << "Caught exception: " << error << "\n"; - } - total++; - } - - typedef void (*EncodingFn)(std::ostream&, int); - - inline char Byte(int ch) - { - return static_cast(static_cast(static_cast(ch))); - } - - void EncodeToUtf8(std::ostream& stream, int ch) - { - if (ch <= 0x7F) - { - stream << Byte(ch); - } - else if (ch <= 0x7FF) - { - stream << Byte(0xC0 | (ch >> 6)); - stream << Byte(0x80 | (ch & 0x3F)); - } - else if (ch <= 0xFFFF) - { - stream << Byte(0xE0 | (ch >> 12)); - stream << Byte(0x80 | ((ch >> 6) & 0x3F)); - stream << Byte(0x80 | (ch & 0x3F)); - } - else if (ch <= 0x1FFFFF) - { - stream << Byte(0xF0 | (ch >> 18)); - stream << Byte(0x80 | ((ch >> 12) & 0x3F)); - stream << Byte(0x80 | ((ch >> 6) & 0x3F)); - stream << Byte(0x80 | (ch & 0x3F)); - } - } - - bool SplitUtf16HighChar(std::ostream& stream, EncodingFn encoding, int ch) - { - int biasedValue = ch - 0x10000; - if (biasedValue < 0) - { - return false; - } - int high = 0xD800 | (biasedValue >> 10); - int low = 0xDC00 | (biasedValue & 0x3FF); - encoding(stream, high); - encoding(stream, low); - return true; - } - - void EncodeToUtf16LE(std::ostream& stream, int ch) - { - if (!SplitUtf16HighChar(stream, &EncodeToUtf16LE, ch)) - { - stream << Byte(ch & 0xFF) << Byte(ch >> 8); - } - } - - void EncodeToUtf16BE(std::ostream& stream, int ch) - { - if (!SplitUtf16HighChar(stream, &EncodeToUtf16BE, ch)) - { - stream << Byte(ch >> 8) << Byte(ch & 0xFF); - } - } - - void EncodeToUtf32LE(std::ostream& stream, int ch) - { - stream << Byte(ch & 0xFF) << Byte((ch >> 8) & 0xFF) - << Byte((ch >> 16) & 0xFF) << Byte((ch >> 24) & 0xFF); - } - - void EncodeToUtf32BE(std::ostream& stream, int ch) - { - stream << Byte((ch >> 24) & 0xFF) << Byte((ch >> 16) & 0xFF) - << Byte((ch >> 8) & 0xFF) << Byte(ch & 0xFF); - } - - class EncodingTester - { - public: - EncodingTester(EncodingFn encoding, bool declareEncoding) - { - if (declareEncoding) - { - encoding(m_yaml, 0xFEFF); - } - - AddEntry(encoding, 0x0021, 0x007E); // Basic Latin - AddEntry(encoding, 0x00A1, 0x00FF); // Latin-1 Supplement - AddEntry(encoding, 0x0660, 0x06FF); // Arabic (largest contiguous block) - - // CJK unified ideographs (multiple lines) - AddEntry(encoding, 0x4E00, 0x4EFF); - AddEntry(encoding, 0x4F00, 0x4FFF); - AddEntry(encoding, 0x5000, 0x51FF); // 512 character line - AddEntry(encoding, 0x5200, 0x54FF); // 768 character line - AddEntry(encoding, 0x5500, 0x58FF); // 1024 character line - - AddEntry(encoding, 0x103A0, 0x103C3); // Old Persian - - m_yaml.seekg(0, std::ios::beg); - } - - std::istream& stream() {return m_yaml;} - const std::vector& entries() {return m_entries;} - - private: - std::stringstream m_yaml; - std::vector m_entries; - - void AddEntry(EncodingFn encoding, int startCh, int endCh) - { - encoding(m_yaml, '-'); - encoding(m_yaml, ' '); - encoding(m_yaml, '|'); - encoding(m_yaml, '\n'); - encoding(m_yaml, ' '); - encoding(m_yaml, ' '); - - std::stringstream entry; - for (int ch = startCh; ch <= endCh; ++ch) - { - encoding(m_yaml, ch); - EncodeToUtf8(entry, ch); - } - encoding(m_yaml, '\n'); - - m_entries.push_back(entry.str()); - } - }; - - void RunEncodingTest(EncodingFn encoding, bool declareEncoding, const std::string& name, int& passed, int& total) - { - EncodingTester tester(encoding, declareEncoding); - std::string error; - bool ok = true; - try { - YAML::Parser parser(tester.stream()); - YAML::Node doc; - parser.GetNextDocument(doc); - - YAML::Iterator itNode = doc.begin(); - std::vector::const_iterator itEntry = tester.entries().begin(); - for (; (itNode != doc.end()) && (itEntry != tester.entries().end()); ++itNode, ++itEntry) - { - std::string stScalarValue; - if (!itNode->GetScalar(stScalarValue) && (stScalarValue == *itEntry)) - { - break; - } - } - - if ((itNode != doc.end()) || (itEntry != tester.entries().end())) - { - ok = false; - } - } catch(const YAML::Exception& e) { - ok = false; - error = e.msg; - } - if(ok) { - passed++; - } else { - std::cout << "Parser test failed: " << name << "\n"; - if(error != "") - std::cout << "Caught exception: " << error << "\n"; - } - total++; - } - } - - bool RunParserTests() - { - int passed = 0; - int total = 0; - RunScalarParserTest(&Parser::SimpleScalar, "simple scalar", passed, total); - RunScalarParserTest(&Parser::MultiLineScalar, "multi-line scalar", passed, total); - RunScalarParserTest(&Parser::LiteralScalar, "literal scalar", passed, total); - RunScalarParserTest(&Parser::FoldedScalar, "folded scalar", passed, total); - RunScalarParserTest(&Parser::ChompedFoldedScalar, "chomped folded scalar", passed, total); - RunScalarParserTest(&Parser::ChompedLiteralScalar, "chomped literal scalar", passed, total); - RunScalarParserTest(&Parser::FoldedScalarWithIndent, "folded scalar with indent", passed, total); - RunScalarParserTest(&Parser::ColonScalar, "colon scalar", passed, total); - RunScalarParserTest(&Parser::QuotedScalar, "quoted scalar", passed, total); - RunScalarParserTest(&Parser::CommaScalar, "comma scalar", passed, total); - RunScalarParserTest(&Parser::DashScalar, "dash scalar", passed, total); - RunScalarParserTest(&Parser::URLScalar, "url scalar", passed, total); - - RunParserTest(&Parser::SimpleSeq, "simple seq", passed, total); - RunParserTest(&Parser::SimpleMap, "simple map", passed, total); - RunParserTest(&Parser::FlowSeq, "flow seq", passed, total); - RunParserTest(&Parser::FlowMap, "flow map", passed, total); - RunParserTest(&Parser::FlowMapWithOmittedKey, "flow map with omitted key", passed, total); - RunParserTest(&Parser::FlowMapWithOmittedValue, "flow map with omitted value", passed, total); - RunParserTest(&Parser::FlowMapWithSoloEntry, "flow map with solo entry", passed, total); - RunParserTest(&Parser::FlowMapEndingWithSoloEntry, "flow map ending with solo entry", passed, total); - RunParserTest(&Parser::QuotedSimpleKeys, "quoted simple keys", passed, total); - RunParserTest(&Parser::CompressedMapAndSeq, "compressed map and seq", passed, total); - RunParserTest(&Parser::NullBlockSeqEntry, "null block seq entry", passed, total); - RunParserTest(&Parser::NullBlockMapKey, "null block map key", passed, total); - RunParserTest(&Parser::NullBlockMapValue, "null block map value", passed, total); - RunParserTest(&Parser::SimpleAlias, "simple alias", passed, total); - RunParserTest(&Parser::AliasWithNull, "alias with null", passed, total); - RunParserTest(&Parser::AnchorInSimpleKey, "anchor in simple key", passed, total); - RunParserTest(&Parser::AliasAsSimpleKey, "alias as simple key", passed, total); - RunParserTest(&Parser::ExplicitDoc, "explicit doc", passed, total); - RunParserTest(&Parser::MultipleDocs, "multiple docs", passed, total); - RunParserTest(&Parser::ExplicitEndDoc, "explicit end doc", passed, total); - RunParserTest(&Parser::MultipleDocsWithSomeExplicitIndicators, "multiple docs with some explicit indicators", passed, total); - - RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed, total); - RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed, total); - RunEncodingTest(&EncodeToUtf16LE, false, "UTF-16LE, no BOM", passed, total); - RunEncodingTest(&EncodeToUtf16LE, true, "UTF-16LE with BOM", passed, total); - RunEncodingTest(&EncodeToUtf16BE, false, "UTF-16BE, no BOM", passed, total); - RunEncodingTest(&EncodeToUtf16BE, true, "UTF-16BE with BOM", passed, total); - RunEncodingTest(&EncodeToUtf32LE, false, "UTF-32LE, no BOM", passed, total); - RunEncodingTest(&EncodeToUtf32LE, true, "UTF-32LE with BOM", passed, total); - RunEncodingTest(&EncodeToUtf32BE, false, "UTF-32BE, no BOM", passed, total); - RunEncodingTest(&EncodeToUtf32BE, true, "UTF-32BE with BOM", passed, total); - - std::cout << "Parser tests: " << passed << "/" << total << " passed\n"; - return passed == total; - } -} - diff --git a/yaml-reader/parsertests.h b/yaml-reader/parsertests.h deleted file mode 100644 index e63a2eb..0000000 --- a/yaml-reader/parsertests.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#ifndef PARSERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#define PARSERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 - -namespace Test { - bool RunParserTests(); -} - -#endif // PARSERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 - diff --git a/yaml-reader/spectests.cpp b/yaml-reader/spectests.cpp deleted file mode 100644 index c4da43f..0000000 --- a/yaml-reader/spectests.cpp +++ /dev/null @@ -1,1280 +0,0 @@ -#include "spectests.h" -#include "yaml.h" -#include -#include -#include -#include - -namespace { - struct TEST { - TEST(): ok(false) {} - TEST(bool ok_): ok(ok_) {} - TEST(const char *error_): ok(false), error(error_) {} - - bool ok; - std::string error; - }; -} - -#define YAML_ASSERT(cond) do { if(!(cond)) return " Assert failed: " #cond; } while(false) -#define PARSE(doc, input) \ - std::stringstream stream(input);\ - YAML::Parser parser(stream);\ - YAML::Node doc;\ - parser.GetNextDocument(doc) -#define PARSE_NEXT(doc) parser.GetNextDocument(doc) - -namespace Test { - namespace { - void RunSpecTest(TEST (*test)(), const std::string& index, const std::string& name, int& passed, int& total) { - TEST ret; - try { - ret = test(); - } catch(const YAML::Exception& e) { - ret.ok = false; - ret.error = " Exception caught: " + e.msg; - } - - if(!ret.ok) { - std::cout << "Spec test " << index << " failed: " << name << "\n"; - std::cout << ret.error << "\n"; - } - - if(ret.ok) - passed++; - total++; - } - } - - namespace Spec { - // 2.1 - TEST SeqScalars() { - std::string input = - "- Mark McGwire\n" - "- Sammy Sosa\n" - "- Ken Griffey"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc[0] == "Mark McGwire"); - YAML_ASSERT(doc[1] == "Sammy Sosa"); - YAML_ASSERT(doc[2] == "Ken Griffey"); - return true; - } - - // 2.2 - TEST MappingScalarsToScalars() { - std::string input = - "hr: 65 # Home runs\n" - "avg: 0.278 # Batting average\n" - "rbi: 147 # Runs Batted In"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["hr"] == "65"); - YAML_ASSERT(doc["avg"] == "0.278"); - YAML_ASSERT(doc["rbi"] == "147"); - return true; - } - - // 2.3 - TEST MappingScalarsToSequences() { - std::string input = - "american:\n" - "- Boston Red Sox\n" - "- Detroit Tigers\n" - "- New York Yankees\n" - "national:\n" - "- New York Mets\n" - "- Chicago Cubs\n" - "- Atlanta Braves"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["american"].size() == 3); - YAML_ASSERT(doc["american"][0] == "Boston Red Sox"); - YAML_ASSERT(doc["american"][1] == "Detroit Tigers"); - YAML_ASSERT(doc["american"][2] == "New York Yankees"); - YAML_ASSERT(doc["national"].size() == 3); - YAML_ASSERT(doc["national"][0] == "New York Mets"); - YAML_ASSERT(doc["national"][1] == "Chicago Cubs"); - YAML_ASSERT(doc["national"][2] == "Atlanta Braves"); - return true; - } - - // 2.4 - TEST SequenceOfMappings() - { - std::string input = - "-\n" - " name: Mark McGwire\n" - " hr: 65\n" - " avg: 0.278\n" - "-\n" - " name: Sammy Sosa\n" - " hr: 63\n" - " avg: 0.288"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc[0].size() == 3); - YAML_ASSERT(doc[0]["name"] == "Mark McGwire"); - YAML_ASSERT(doc[0]["hr"] == "65"); - YAML_ASSERT(doc[0]["avg"] == "0.278"); - YAML_ASSERT(doc[1].size() == 3); - YAML_ASSERT(doc[1]["name"] == "Sammy Sosa"); - YAML_ASSERT(doc[1]["hr"] == "63"); - YAML_ASSERT(doc[1]["avg"] == "0.288"); - return true; - } - - // 2.5 - TEST SequenceOfSequences() - { - std::string input = - "- [name , hr, avg ]\n" - "- [Mark McGwire, 65, 0.278]\n" - "- [Sammy Sosa , 63, 0.288]"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc[0].size() == 3); - YAML_ASSERT(doc[0][0] == "name"); - YAML_ASSERT(doc[0][1] == "hr"); - YAML_ASSERT(doc[0][2] == "avg"); - YAML_ASSERT(doc[1].size() == 3); - YAML_ASSERT(doc[1][0] == "Mark McGwire"); - YAML_ASSERT(doc[1][1] == "65"); - YAML_ASSERT(doc[1][2] == "0.278"); - YAML_ASSERT(doc[2].size() == 3); - YAML_ASSERT(doc[2][0] == "Sammy Sosa"); - YAML_ASSERT(doc[2][1] == "63"); - YAML_ASSERT(doc[2][2] == "0.288"); - return true; - } - - // 2.6 - TEST MappingOfMappings() - { - std::string input = - "Mark McGwire: {hr: 65, avg: 0.278}\n" - "Sammy Sosa: {\n" - " hr: 63,\n" - " avg: 0.288\n" - " }"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["Mark McGwire"].size() == 2); - YAML_ASSERT(doc["Mark McGwire"]["hr"] == "65"); - YAML_ASSERT(doc["Mark McGwire"]["avg"] == "0.278"); - YAML_ASSERT(doc["Sammy Sosa"].size() == 2); - YAML_ASSERT(doc["Sammy Sosa"]["hr"] == "63"); - YAML_ASSERT(doc["Sammy Sosa"]["avg"] == "0.288"); - return true; - } - - // 2.7 - TEST TwoDocumentsInAStream() - { - std::string input = - "# Ranking of 1998 home runs\n" - "---\n" - "- Mark McGwire\n" - "- Sammy Sosa\n" - "- Ken Griffey\n" - "\n" - "# Team ranking\n" - "---\n" - "- Chicago Cubs\n" - "- St Louis Cardinals"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc[0] == "Mark McGwire"); - YAML_ASSERT(doc[1] == "Sammy Sosa"); - YAML_ASSERT(doc[2] == "Ken Griffey"); - - PARSE_NEXT(doc); - YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc[0] == "Chicago Cubs"); - YAML_ASSERT(doc[1] == "St Louis Cardinals"); - return true; - } - - // 2.8 - TEST PlayByPlayFeed() - { - std::string input = - "---\n" - "time: 20:03:20\n" - "player: Sammy Sosa\n" - "action: strike (miss)\n" - "...\n" - "---\n" - "time: 20:03:47\n" - "player: Sammy Sosa\n" - "action: grand slam\n" - "..."; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["time"] == "20:03:20"); - YAML_ASSERT(doc["player"] == "Sammy Sosa"); - YAML_ASSERT(doc["action"] == "strike (miss)"); - - PARSE_NEXT(doc); - YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["time"] == "20:03:47"); - YAML_ASSERT(doc["player"] == "Sammy Sosa"); - YAML_ASSERT(doc["action"] == "grand slam"); - return true; - } - - // 2.9 - TEST SingleDocumentWithTwoComments() - { - std::string input = - "---\n" - "hr: # 1998 hr ranking\n" - " - Mark McGwire\n" - " - Sammy Sosa\n" - "rbi:\n" - " # 1998 rbi ranking\n" - " - Sammy Sosa\n" - " - Ken Griffey"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["hr"].size() == 2); - YAML_ASSERT(doc["hr"][0] == "Mark McGwire"); - YAML_ASSERT(doc["hr"][1] == "Sammy Sosa"); - YAML_ASSERT(doc["rbi"].size() == 2); - YAML_ASSERT(doc["rbi"][0] == "Sammy Sosa"); - YAML_ASSERT(doc["rbi"][1] == "Ken Griffey"); - return true; - } - - // 2.10 - TEST SimpleAnchor() - { - std::string input = - "---\n" - "hr:\n" - " - Mark McGwire\n" - " # Following node labeled SS\n" - " - &SS Sammy Sosa\n" - "rbi:\n" - " - *SS # Subsequent occurrence\n" - " - Ken Griffey"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["hr"].size() == 2); - YAML_ASSERT(doc["hr"][0] == "Mark McGwire"); - YAML_ASSERT(doc["hr"][1] == "Sammy Sosa"); - YAML_ASSERT(doc["rbi"].size() == 2); - YAML_ASSERT(doc["rbi"][0] == "Sammy Sosa"); - YAML_ASSERT(doc["rbi"][1] == "Ken Griffey"); - return true; - } - - struct Pair { - Pair() {} - Pair(const std::string& f, const std::string& s): first(f), second(s) {} - std::string first, second; - }; - - bool operator == (const Pair& p, const Pair& q) { - return p.first == q.first && p.second == q.second; - } - - void operator >> (const YAML::Node& node, Pair& p) { - node[0] >> p.first; - node[1] >> p.second; - } - - // 2.11 - TEST MappingBetweenSequences() - { - std::string input = - "? - Detroit Tigers\n" - " - Chicago cubs\n" - ":\n" - " - 2001-07-23\n" - "\n" - "? [ New York Yankees,\n" - " Atlanta Braves ]\n" - ": [ 2001-07-02, 2001-08-12,\n" - " 2001-08-14 ]"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc[Pair("Detroit Tigers", "Chicago cubs")].size() == 1); - YAML_ASSERT(doc[Pair("Detroit Tigers", "Chicago cubs")][0] == "2001-07-23"); - YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")].size() == 3); - YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][0] == "2001-07-02"); - YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][1] == "2001-08-12"); - YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][2] == "2001-08-14"); - return true; - } - - // 2.12 - TEST CompactNestedMapping() - { - std::string input = - "---\n" - "# Products purchased\n" - "- item : Super Hoop\n" - " quantity: 1\n" - "- item : Basketball\n" - " quantity: 4\n" - "- item : Big Shoes\n" - " quantity: 1"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc[0].size() == 2); - YAML_ASSERT(doc[0]["item"] == "Super Hoop"); - YAML_ASSERT(doc[0]["quantity"] == 1); - YAML_ASSERT(doc[1].size() == 2); - YAML_ASSERT(doc[1]["item"] == "Basketball"); - YAML_ASSERT(doc[1]["quantity"] == 4); - YAML_ASSERT(doc[2].size() == 2); - YAML_ASSERT(doc[2]["item"] == "Big Shoes"); - YAML_ASSERT(doc[2]["quantity"] == 1); - return true; - } - - // 2.13 - TEST InLiteralsNewlinesArePreserved() - { - std::string input = - "# ASCII Art\n" - "--- |\n" - " \\//||\\/||\n" - " // || ||__"; - - PARSE(doc, input); - YAML_ASSERT(doc == - "\\//||\\/||\n" - "// || ||__"); - return true; - } - - // 2.14 - TEST InFoldedScalarsNewlinesBecomeSpaces() - { - std::string input = - "--- >\n" - " Mark McGwire's\n" - " year was crippled\n" - " by a knee injury."; - - PARSE(doc, input); - YAML_ASSERT(doc == "Mark McGwire's year was crippled by a knee injury."); - return true; - } - - // 2.15 - TEST FoldedNewlinesArePreservedForMoreIndentedAndBlankLines() - { - std::string input = - ">\n" - " Sammy Sosa completed another\n" - " fine season with great stats.\n" - " \n" - " 63 Home Runs\n" - " 0.288 Batting Average\n" - " \n" - " What a year!"; - - PARSE(doc, input); - YAML_ASSERT(doc == - "Sammy Sosa completed another fine season with great stats.\n\n" - " 63 Home Runs\n" - " 0.288 Batting Average\n\n" - "What a year!"); - return true; - } - - // 2.16 - TEST IndentationDeterminesScope() - { - std::string input = - "name: Mark McGwire\n" - "accomplishment: >\n" - " Mark set a major league\n" - " home run record in 1998.\n" - "stats: |\n" - " 65 Home Runs\n" - " 0.278 Batting Average\n"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["name"] == "Mark McGwire"); - YAML_ASSERT(doc["accomplishment"] == "Mark set a major league home run record in 1998.\n"); - YAML_ASSERT(doc["stats"] == "65 Home Runs\n0.278 Batting Average\n"); - return true; - } - - // 2.17 - TEST QuotedScalars() - { - std::string input = - "unicode: \"Sosa did fine.\\u263A\"\n" - "control: \"\\b1998\\t1999\\t2000\\n\"\n" - "hex esc: \"\\x0d\\x0a is \\r\\n\"\n" - "\n" - "single: '\"Howdy!\" he cried.'\n" - "quoted: ' # Not a ''comment''.'\n" - "tie-fighter: '|\\-*-/|'"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 6); - YAML_ASSERT(doc["unicode"] == "Sosa did fine.\xe2\x98\xba"); - YAML_ASSERT(doc["control"] == "\b1998\t1999\t2000\n"); - YAML_ASSERT(doc["hex esc"] == "\x0d\x0a is \r\n"); - YAML_ASSERT(doc["single"] == "\"Howdy!\" he cried."); - YAML_ASSERT(doc["quoted"] == " # Not a 'comment'."); - YAML_ASSERT(doc["tie-fighter"] == "|\\-*-/|"); - return true; - } - - // 2.18 - TEST MultiLineFlowScalars() - { - std::string input = - "plain:\n" - " This unquoted scalar\n" - " spans many lines.\n" - "\n" - "quoted: \"So does this\n" - " quoted scalar.\\n\""; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["plain"] == "This unquoted scalar spans many lines."); - YAML_ASSERT(doc["quoted"] == "So does this quoted scalar.\n"); - return true; - } - - // TODO: 2.19 - 2.26 tags - - // 2.27 - TEST Invoice() - { - std::string input = - "--- !\n" - "invoice: 34843\n" - "date : 2001-01-23\n" - "bill-to: &id001\n" - " given : Chris\n" - " family : Dumars\n" - " address:\n" - " lines: |\n" - " 458 Walkman Dr.\n" - " Suite #292\n" - " city : Royal Oak\n" - " state : MI\n" - " postal : 48046\n" - "ship-to: *id001\n" - "product:\n" - " - sku : BL394D\n" - " quantity : 4\n" - " description : Basketball\n" - " price : 450.00\n" - " - sku : BL4438H\n" - " quantity : 1\n" - " description : Super Hoop\n" - " price : 2392.00\n" - "tax : 251.42\n" - "total: 4443.52\n" - "comments:\n" - " Late afternoon is best.\n" - " Backup contact is Nancy\n" - " Billsmer @ 338-4338."; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 8); - YAML_ASSERT(doc["invoice"] == 34843); - YAML_ASSERT(doc["date"] == "2001-01-23"); - YAML_ASSERT(doc["bill-to"].size() == 3); - YAML_ASSERT(doc["bill-to"]["given"] == "Chris"); - YAML_ASSERT(doc["bill-to"]["family"] == "Dumars"); - YAML_ASSERT(doc["bill-to"]["address"].size() == 4); - YAML_ASSERT(doc["bill-to"]["address"]["lines"] == "458 Walkman Dr.\nSuite #292\n"); - YAML_ASSERT(doc["bill-to"]["address"]["city"] == "Royal Oak"); - YAML_ASSERT(doc["bill-to"]["address"]["state"] == "MI"); - YAML_ASSERT(doc["bill-to"]["address"]["postal"] == "48046"); - YAML_ASSERT(doc["ship-to"].size() == 3); - YAML_ASSERT(doc["ship-to"]["given"] == "Chris"); - YAML_ASSERT(doc["ship-to"]["family"] == "Dumars"); - YAML_ASSERT(doc["ship-to"]["address"].size() == 4); - YAML_ASSERT(doc["ship-to"]["address"]["lines"] == "458 Walkman Dr.\nSuite #292\n"); - YAML_ASSERT(doc["ship-to"]["address"]["city"] == "Royal Oak"); - YAML_ASSERT(doc["ship-to"]["address"]["state"] == "MI"); - YAML_ASSERT(doc["ship-to"]["address"]["postal"] == "48046"); - YAML_ASSERT(doc["product"].size() == 2); - YAML_ASSERT(doc["product"][0].size() == 4); - YAML_ASSERT(doc["product"][0]["sku"] == "BL394D"); - YAML_ASSERT(doc["product"][0]["quantity"] == 4); - YAML_ASSERT(doc["product"][0]["description"] == "Basketball"); - YAML_ASSERT(doc["product"][0]["price"] == "450.00"); - YAML_ASSERT(doc["product"][1].size() == 4); - YAML_ASSERT(doc["product"][1]["sku"] == "BL4438H"); - YAML_ASSERT(doc["product"][1]["quantity"] == 1); - YAML_ASSERT(doc["product"][1]["description"] == "Super Hoop"); - YAML_ASSERT(doc["product"][1]["price"] == "2392.00"); - YAML_ASSERT(doc["tax"] == "251.42"); - YAML_ASSERT(doc["total"] == "4443.52"); - YAML_ASSERT(doc["comments"] == "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338."); - return true; - } - - // 2.28 - TEST LogFile() - { - std::string input = - "---\n" - "Time: 2001-11-23 15:01:42 -5\n" - "User: ed\n" - "Warning:\n" - " This is an error message\n" - " for the log file\n" - "---\n" - "Time: 2001-11-23 15:02:31 -5\n" - "User: ed\n" - "Warning:\n" - " A slightly different error\n" - " message.\n" - "---\n" - "Date: 2001-11-23 15:03:17 -5\n" - "User: ed\n" - "Fatal:\n" - " Unknown variable \"bar\"\n" - "Stack:\n" - " - file: TopClass.py\n" - " line: 23\n" - " code: |\n" - " x = MoreObject(\"345\\n\")\n" - " - file: MoreClass.py\n" - " line: 58\n" - " code: |-\n" - " foo = bar"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["Time"] == "2001-11-23 15:01:42 -5"); - YAML_ASSERT(doc["User"] == "ed"); - YAML_ASSERT(doc["Warning"] == "This is an error message for the log file"); - - PARSE_NEXT(doc); - YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["Time"] == "2001-11-23 15:02:31 -5"); - YAML_ASSERT(doc["User"] == "ed"); - YAML_ASSERT(doc["Warning"] == "A slightly different error message."); - - PARSE_NEXT(doc); - YAML_ASSERT(doc.size() == 4); - YAML_ASSERT(doc["Date"] == "2001-11-23 15:03:17 -5"); - YAML_ASSERT(doc["User"] == "ed"); - YAML_ASSERT(doc["Fatal"] == "Unknown variable \"bar\""); - YAML_ASSERT(doc["Stack"].size() == 2); - YAML_ASSERT(doc["Stack"][0].size() == 3); - YAML_ASSERT(doc["Stack"][0]["file"] == "TopClass.py"); - YAML_ASSERT(doc["Stack"][0]["line"] == "23"); - YAML_ASSERT(doc["Stack"][0]["code"] == "x = MoreObject(\"345\\n\")\n"); - YAML_ASSERT(doc["Stack"][1].size() == 3); - YAML_ASSERT(doc["Stack"][1]["file"] == "MoreClass.py"); - YAML_ASSERT(doc["Stack"][1]["line"] == "58"); - YAML_ASSERT(doc["Stack"][1]["code"] == "foo = bar"); - return true; - } - - // TODO: 5.1 - 5.2 BOM - - // 5.3 - TEST BlockStructureIndicators() - { - std::string input = - "sequence:\n" - "- one\n" - "- two\n" - "mapping:\n" - " ? sky\n" - " : blue\n" - " sea : green"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["sequence"].size() == 2); - YAML_ASSERT(doc["sequence"][0] == "one"); - YAML_ASSERT(doc["sequence"][1] == "two"); - YAML_ASSERT(doc["mapping"].size() == 2); - YAML_ASSERT(doc["mapping"]["sky"] == "blue"); - YAML_ASSERT(doc["mapping"]["sea"] == "green"); - return true; - } - - // 5.4 - TEST FlowStructureIndicators() - { - std::string input = - "sequence: [ one, two, ]\n" - "mapping: { sky: blue, sea: green }"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["sequence"].size() == 2); - YAML_ASSERT(doc["sequence"][0] == "one"); - YAML_ASSERT(doc["sequence"][1] == "two"); - YAML_ASSERT(doc["mapping"].size() == 2); - YAML_ASSERT(doc["mapping"]["sky"] == "blue"); - YAML_ASSERT(doc["mapping"]["sea"] == "green"); - return true; - } - - // TODO: 5.5 comment only - - // 5.6 - TEST NodePropertyIndicators() - { - std::string input = - "anchored: !local &anchor value\n" - "alias: *anchor"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["anchored"] == "value"); // TODO: assert tag - YAML_ASSERT(doc["alias"] == "value"); - return true; - } - - // 5.7 - TEST BlockScalarIndicators() - { - std::string input = - "literal: |\n" - " some\n" - " text\n" - "folded: >\n" - " some\n" - " text\n"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["literal"] == "some\ntext\n"); - YAML_ASSERT(doc["folded"] == "some text\n"); - return true; - } - - // 5.8 - TEST QuotedScalarIndicators() - { - std::string input = - "single: 'text'\n" - "double: \"text\""; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["single"] == "text"); - YAML_ASSERT(doc["double"] == "text"); - return true; - } - - // TODO: 5.9 directive - // TODO: 5.10 reserved indicator - - // 5.11 - TEST LineBreakCharacters() - { - std::string input = - "|\n" - " Line break (no glyph)\n" - " Line break (glyphed)\n"; - - PARSE(doc, input); - YAML_ASSERT(doc == "Line break (no glyph)\nLine break (glyphed)\n"); - return true; - } - - // 5.12 - TEST TabsAndSpaces() - { - std::string input = - "# Tabs and spaces\n" - "quoted: \"Quoted\t\"\n" - "block: |\n" - " void main() {\n" - " \tprintf(\"Hello, world!\\n\");\n" - " }"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["quoted"] == "Quoted\t"); - YAML_ASSERT(doc["block"] == - "void main() {\n" - "\tprintf(\"Hello, world!\\n\");\n" - "}"); - return true; - } - - // 5.13 - TEST EscapedCharacters() - { - std::string input = - "\"Fun with \\\\\n" - "\\\" \\a \\b \\e \\f \\\n" - "\\n \\r \\t \\v \\0 \\\n" - "\\ \\_ \\N \\L \\P \\\n" - "\\x41 \\u0041 \\U00000041\""; - - PARSE(doc, input); - YAML_ASSERT(doc == "Fun with \x5C \x22 \x07 \x08 \x1B \x0C \x0A \x0D \x09 \x0B " + std::string("\x00", 1) + " \x20 \xA0 \x85 \xe2\x80\xa8 \xe2\x80\xa9 A A A"); - return true; - } - - // 5.14 - TEST InvalidEscapedCharacters() - { - std::string input = - "Bad escapes:\n" - " \"\\c\n" - " \\xq-\""; - - std::stringstream stream(input); - try { - YAML::Parser parser(stream); - YAML::Node doc; - parser.GetNextDocument(doc); - } catch(const YAML::ParserException& e) { - YAML_ASSERT(e.msg == YAML::ErrorMsg::INVALID_ESCAPE + "c"); - return true; - } - - return false; - } - - // 6.1 - TEST IndentationSpaces() - { - std::string input = - " # Leading comment line spaces are\n" - " # neither content nor indentation.\n" - " \n" - "Not indented:\n" - " By one space: |\n" - " By four\n" - " spaces\n" - " Flow style: [ # Leading spaces\n" - " By two, # in flow style\n" - " Also by two, # are neither\n" - " \tStill by two # content nor\n" - " ] # indentation."; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 1); - YAML_ASSERT(doc["Not indented"].size() == 2); - YAML_ASSERT(doc["Not indented"]["By one space"] == "By four\n spaces\n"); - YAML_ASSERT(doc["Not indented"]["Flow style"].size() == 3); - YAML_ASSERT(doc["Not indented"]["Flow style"][0] == "By two"); - YAML_ASSERT(doc["Not indented"]["Flow style"][1] == "Also by two"); - YAML_ASSERT(doc["Not indented"]["Flow style"][2] == "Still by two"); - return true; - } - - // 6.2 - TEST IndentationIndicators() - { - std::string input = - "? a\n" - ": -\tb\n" - " - -\tc\n" - " - d"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 1); - YAML_ASSERT(doc["a"].size() == 2); - YAML_ASSERT(doc["a"][0] == "b"); - YAML_ASSERT(doc["a"][1].size() == 2); - YAML_ASSERT(doc["a"][1][0] == "c"); - YAML_ASSERT(doc["a"][1][1] == "d"); - return true; - } - - // 6.3 - TEST SeparationSpaces() - { - std::string input = - "- foo:\t bar\n" - "- - baz\n" - " -\tbaz"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc[0].size() == 1); - YAML_ASSERT(doc[0]["foo"] == "bar"); - YAML_ASSERT(doc[1].size() == 2); - YAML_ASSERT(doc[1][0] == "baz"); - YAML_ASSERT(doc[1][1] == "baz"); - return true; - } - - // 6.4 - TEST LinePrefixes() - { - std::string input = - "plain: text\n" - " lines\n" - "quoted: \"text\n" - " \tlines\"\n" - "block: |\n" - " text\n" - " \tlines\n"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["plain"] == "text lines"); - YAML_ASSERT(doc["quoted"] == "text lines"); - YAML_ASSERT(doc["block"] == "text\n \tlines\n"); - return true; - } - - // 6.5 - TEST EmptyLines() - { - std::string input = - "Folding:\n" - " \"Empty line\n" - " \t\n" - " as a line feed\"\n" - "Chomping: |\n" - " Clipped empty lines\n" - " "; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["Folding"] == "Empty line\nas a line feed"); - YAML_ASSERT(doc["Chomping"] == "Clipped empty lines\n"); - return true; - } - - // 6.6 - TEST LineFolding() - { - std::string input = - ">-\n" - " trimmed\n" - " \n" - " \n" - "\n" - " as\n" - " space"; - - PARSE(doc, input); - YAML_ASSERT(doc == "trimmed\n\n\nas space"); - return true; - } - - // 6.7 - TEST BlockFolding() - { - std::string input = - ">\n" - " foo \n" - " \n" - " \t bar\n" - "\n" - " baz\n"; - - PARSE(doc, input); - YAML_ASSERT(doc == "foo \n\n\t bar\n\nbaz\n"); - return true; - } - - // 6.8 - TEST FlowFolding() - { - std::string input = - "\"\n" - " foo \n" - " \n" - " \t bar\n" - "\n" - " baz\n" - "\""; - - PARSE(doc, input); - YAML_ASSERT(doc == " foo\nbar\nbaz "); - return true; - } - - // 6.9 - TEST SeparatedComment() - { - std::string input = - "key: # Comment\n" - " value"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 1); - YAML_ASSERT(doc["key"] == "value"); - return true; - } - - // 6.10 - TEST CommentLines() - { - std::string input = - " # Comment\n" - " \n" - "\n"; - std::stringstream stream(input); - YAML::Parser parser(stream); - - YAML_ASSERT(!parser); - return true; - } - - // 6.11 - TEST MultiLineComments() - { - std::string input = - "key: # Comment\n" - " # lines\n" - " value\n" - "\n"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 1); - YAML_ASSERT(doc["key"] == "value"); - return true; - } - - struct StringMap { - typedef std::map Map; - Map _; - }; - - bool operator == (const StringMap& m, const StringMap& n) { - return m._ == n._; - } - - void operator >> (const YAML::Node& node, StringMap& m) { - m._.clear(); - for(YAML::Iterator it=node.begin();it!=node.end();++it) { - std::string key = it.first(); - std::string value = it.second(); - m._[key] = value; - } - } - - - // 6.12 - TEST SeparationSpacesII() - { - std::string input = - "{ first: Sammy, last: Sosa }:\n" - "# Statistics:\n" - " hr: # Home runs\n" - " 65\n" - " avg: # Average\n" - " 0.278"; - - PARSE(doc, input); - StringMap key; - key._["first"] = "Sammy"; - key._["last"] = "Sosa"; - YAML_ASSERT(doc.size() == 1); - YAML_ASSERT(doc[key].size() == 2); - YAML_ASSERT(doc[key]["hr"] == 65); - YAML_ASSERT(doc[key]["avg"] == "0.278"); - return true; - } - - // TODO: 6.13 - 6.17 directives - // TODO: 6.18 - 6.28 tags - - // 6.29 - TEST NodeAnchors() - { - std::string input = - "First occurrence: &anchor Value\n" - "Second occurrence: *anchor"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["First occurrence"] == "Value"); - YAML_ASSERT(doc["Second occurrence"] == "Value"); - return true; - } - - // 7.1 - TEST AliasNodes() - { - std::string input = - "First occurrence: &anchor Foo\n" - "Second occurrence: *anchor\n" - "Override anchor: &anchor Bar\n" - "Reuse anchor: *anchor"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 4); - YAML_ASSERT(doc["First occurrence"] == "Foo"); - YAML_ASSERT(doc["Second occurrence"] == "Foo"); - YAML_ASSERT(doc["Override anchor"] == "Bar"); - YAML_ASSERT(doc["Reuse anchor"] == "Bar"); - return true; - } - - // 7.2 - TEST EmptyNodes() - { - std::string input = - "{\n" - " foo : !!str,\n" - " !!str : bar,\n" - "}"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["foo"] == ""); // TODO: check tag - YAML_ASSERT(doc[""] == "bar"); - return true; - } - - // 7.3 - TEST CompletelyEmptyNodes() - { - std::string input = - "{\n" - " ? foo :,\n" - " : bar,\n" - "}\n"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(IsNull(doc["foo"])); - YAML_ASSERT(doc[YAML::Null] == "bar"); - return true; - } - - // 7.4 - TEST DoubleQuotedImplicitKeys() - { - std::string input = - "\"implicit block key\" : [\n" - " \"implicit flow key\" : value,\n" - " ]"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 1); - YAML_ASSERT(doc["implicit block key"].size() == 1); - YAML_ASSERT(doc["implicit block key"][0].size() == 1); - YAML_ASSERT(doc["implicit block key"][0]["implicit flow key"] == "value"); - return true; - } - - // 7.5 - TEST DoubleQuotedLineBreaks() - { - std::string input = - "\"folded \n" - "to a space,\t\n" - " \n" - "to a line feed, or \t\\\n" - " \\ \tnon-content\""; - - PARSE(doc, input); - YAML_ASSERT(doc == "folded to a space,\nto a line feed, or \t \tnon-content"); - return true; - } - - // 7.6 - TEST DoubleQuotedLines() - { - std::string input = - "\" 1st non-empty\n" - "\n" - " 2nd non-empty \n" - "\t3rd non-empty \""; - - PARSE(doc, input); - YAML_ASSERT(doc == " 1st non-empty\n2nd non-empty 3rd non-empty "); - return true; - } - - // 7.7 - TEST SingleQuotedCharacters() - { - std::string input = " 'here''s to \"quotes\"'"; - - PARSE(doc, input); - YAML_ASSERT(doc == "here's to \"quotes\""); - return true; - } - - // 7.8 - TEST SingleQuotedImplicitKeys() - { - std::string input = - "'implicit block key' : [\n" - " 'implicit flow key' : value,\n" - " ]"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 1); - YAML_ASSERT(doc["implicit block key"].size() == 1); - YAML_ASSERT(doc["implicit block key"][0].size() == 1); - YAML_ASSERT(doc["implicit block key"][0]["implicit flow key"] == "value"); - return true; - } - - // 7.9 - TEST SingleQuotedLines() - { - std::string input = - "' 1st non-empty\n" - "\n" - " 2nd non-empty \n" - "\t3rd non-empty '"; - - PARSE(doc, input); - YAML_ASSERT(doc == " 1st non-empty\n2nd non-empty 3rd non-empty "); - return true; - } - - // 7.10 - TEST PlainCharacters() - { - std::string input = - "# Outside flow collection:\n" - "- ::vector\n" - "- \": - ()\"\n" - "- Up, up, and away!\n" - "- -123\n" - "- http://example.com/foo#bar\n" - "# Inside flow collection:\n" - "- [ ::vector,\n" - " \": - ()\",\n" - " \"Up, up, and away!\",\n" - " -123,\n" - " http://example.com/foo#bar ]"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 6); - YAML_ASSERT(doc[0] == "::vector"); - YAML_ASSERT(doc[1] == ": - ()"); - YAML_ASSERT(doc[2] == "Up, up, and away!"); - YAML_ASSERT(doc[3] == -123); - YAML_ASSERT(doc[4] == "http://example.com/foo#bar"); - YAML_ASSERT(doc[5].size() == 5); - YAML_ASSERT(doc[5][0] == "::vector"); - YAML_ASSERT(doc[5][1] == ": - ()"); - YAML_ASSERT(doc[5][2] == "Up, up, and away!"); - YAML_ASSERT(doc[5][3] == -123); - YAML_ASSERT(doc[5][4] == "http://example.com/foo#bar"); - return true; - } - - // 7.11 - TEST PlainImplicitKeys() - { - std::string input = - "implicit block key : [\n" - " implicit flow key : value,\n" - " ]"; - - PARSE(doc, input); - YAML_ASSERT(doc.size() == 1); - YAML_ASSERT(doc["implicit block key"].size() == 1); - YAML_ASSERT(doc["implicit block key"][0].size() == 1); - YAML_ASSERT(doc["implicit block key"][0]["implicit flow key"] == "value"); - return true; - } - - // 7.12 - TEST PlainLines() - { - std::string input = - "1st non-empty\n" - "\n" - " 2nd non-empty \n" - "\t3rd non-empty"; - - PARSE(doc, input); - YAML_ASSERT(doc == "1st non-empty\n2nd non-empty 3rd non-empty"); - return true; - } - } - - bool RunSpecTests() - { - int passed = 0; - int total = 0; - RunSpecTest(&Spec::SeqScalars, "2.1", "Sequence of Scalars", passed, total); - RunSpecTest(&Spec::MappingScalarsToScalars, "2.2", "Mapping Scalars to Scalars", passed, total); - RunSpecTest(&Spec::MappingScalarsToSequences, "2.3", "Mapping Scalars to Sequences", passed, total); - RunSpecTest(&Spec::SequenceOfMappings, "2.4", "Sequence of Mappings", passed, total); - RunSpecTest(&Spec::SequenceOfSequences, "2.5", "Sequence of Sequences", passed, total); - RunSpecTest(&Spec::MappingOfMappings, "2.6", "Mapping of Mappings", passed, total); - RunSpecTest(&Spec::TwoDocumentsInAStream, "2.7", "Two Documents in a Stream", passed, total); - RunSpecTest(&Spec::PlayByPlayFeed, "2.8", "Play by Play Feed from a Game", passed, total); - RunSpecTest(&Spec::SingleDocumentWithTwoComments, "2.9", "Single Document with Two Comments", passed, total); - RunSpecTest(&Spec::SimpleAnchor, "2.10", "Node for \"Sammy Sosa\" appears twice in this document", passed, total); - RunSpecTest(&Spec::MappingBetweenSequences, "2.11", "Mapping between Sequences", passed, total); - RunSpecTest(&Spec::CompactNestedMapping, "2.12", "Compact Nested Mapping", passed, total); - RunSpecTest(&Spec::InLiteralsNewlinesArePreserved, "2.13", "In literals, newlines are preserved", passed, total); - RunSpecTest(&Spec::InFoldedScalarsNewlinesBecomeSpaces, "2.14", "In folded scalars, newlines become spaces", passed, total); - RunSpecTest(&Spec::FoldedNewlinesArePreservedForMoreIndentedAndBlankLines, "2.15", "Folded newlines are preserved for \"more indented\" and blank lines", passed, total); - RunSpecTest(&Spec::IndentationDeterminesScope, "2.16", "Indentation determines scope", passed, total); - RunSpecTest(&Spec::QuotedScalars, "2.17", "Quoted scalars", passed, total); - RunSpecTest(&Spec::MultiLineFlowScalars, "2.18", "Multi-line flow scalars", passed, total); - - RunSpecTest(&Spec::Invoice, "2.27", "Invoice", passed, total); - RunSpecTest(&Spec::LogFile, "2.28", "Log File", passed, total); - - RunSpecTest(&Spec::BlockStructureIndicators, "5.3", "Block Structure Indicators", passed, total); - RunSpecTest(&Spec::FlowStructureIndicators, "5.4", "Flow Structure Indicators", passed, total); - RunSpecTest(&Spec::NodePropertyIndicators, "5.6", "Node Property Indicators", passed, total); - RunSpecTest(&Spec::BlockScalarIndicators, "5.7", "Block Scalar Indicators", passed, total); - RunSpecTest(&Spec::QuotedScalarIndicators, "5.8", "Quoted Scalar Indicators", passed, total); - RunSpecTest(&Spec::LineBreakCharacters, "5.11", "Line Break Characters", passed, total); - RunSpecTest(&Spec::TabsAndSpaces, "5.12", "Tabs and Spaces", passed, total); - RunSpecTest(&Spec::EscapedCharacters, "5.13", "Escaped Characters", passed, total); - RunSpecTest(&Spec::InvalidEscapedCharacters, "5.14", "Invalid Escaped Characters", passed, total); - - RunSpecTest(&Spec::IndentationSpaces, "6.1", "Indentation Spaces", passed, total); - RunSpecTest(&Spec::IndentationIndicators, "6.2", "Indentation Indicators", passed, total); - RunSpecTest(&Spec::SeparationSpaces, "6.3", "Separation Spaces", passed, total); - RunSpecTest(&Spec::LinePrefixes, "6.4", "Line Prefixes", passed, total); - RunSpecTest(&Spec::EmptyLines, "6.5", "Empty Lines", passed, total); - RunSpecTest(&Spec::LineFolding, "6.6", "Line Folding", passed, total); - RunSpecTest(&Spec::BlockFolding, "6.7", "Block Folding", passed, total); - RunSpecTest(&Spec::FlowFolding, "6.8", "Flow Folding", passed, total); - RunSpecTest(&Spec::SeparatedComment, "6.9", "Separated Comment", passed, total); - RunSpecTest(&Spec::CommentLines, "6.10", "Comment Lines", passed, total); - RunSpecTest(&Spec::SeparationSpacesII, "6.11", "Separation Spaces", passed, total); - - RunSpecTest(&Spec::NodeAnchors, "6.29", "Node Anchors", passed, total); - - RunSpecTest(&Spec::AliasNodes, "7.1", "Alias Nodes", passed, total); - RunSpecTest(&Spec::EmptyNodes, "7.2", "Empty Nodes", passed, total); - RunSpecTest(&Spec::CompletelyEmptyNodes, "7.3", "Completely Empty Nodes", passed, total); - RunSpecTest(&Spec::DoubleQuotedImplicitKeys, "7.4", "Double Quoted Implicit Keys", passed, total); - RunSpecTest(&Spec::DoubleQuotedLineBreaks, "7.5", "Double Quoted Line Breaks", passed, total); - RunSpecTest(&Spec::DoubleQuotedLines, "7.6", "Double Quoted Lines", passed, total); - RunSpecTest(&Spec::SingleQuotedCharacters, "7.7", "Single Quoted Characters", passed, total); - RunSpecTest(&Spec::SingleQuotedImplicitKeys, "7.8", "Single Quoted Implicit Keys", passed, total); - RunSpecTest(&Spec::SingleQuotedLines, "7.9", "Single Quoted Lines", passed, total); - RunSpecTest(&Spec::PlainCharacters, "7.10", "Plain Characters", passed, total); - RunSpecTest(&Spec::PlainImplicitKeys, "7.11", "Plain Implicit Keys", passed, total); - RunSpecTest(&Spec::PlainLines, "7.12", "Plain Lines", passed, total); - - std::cout << "Spec tests: " << passed << "/" << total << " passed\n"; - return passed == total; - } - -} - diff --git a/yaml-reader/spectests.h b/yaml-reader/spectests.h deleted file mode 100644 index fcb1fb4..0000000 --- a/yaml-reader/spectests.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#ifndef SPECTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#define SPECTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 - -namespace Test { - bool RunSpecTests(); -} - -#endif // SPECTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 - diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp deleted file mode 100644 index 492a5d1..0000000 --- a/yaml-reader/tests.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "tests.h" -#include "emittertests.h" -#include "parsertests.h" -#include "spectests.h" -#include "yaml.h" -#include -#include -#include -#include - -namespace Test -{ - void RunAll() - { - bool passed = true; - if(!RunParserTests()) - passed = false; - - if(!RunEmitterTests()) - passed = false; - - if(!RunSpecTests()) - passed = false; - - if(passed) - std::cout << "All tests passed!\n"; - } -} - diff --git a/yaml-reader/tests.h b/yaml-reader/tests.h deleted file mode 100644 index 0d39007..0000000 --- a/yaml-reader/tests.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#ifndef TESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#define TESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 - -#include - -namespace Test { - void RunAll(); - - namespace Parser { - // scalar tests - void SimpleScalar(std::string& inputScalar, std::string& desiredOutput); - void MultiLineScalar(std::string& inputScalar, std::string& desiredOutput); - void LiteralScalar(std::string& inputScalar, std::string& desiredOutput); - void FoldedScalar(std::string& inputScalar, std::string& desiredOutput); - void ChompedFoldedScalar(std::string& inputScalar, std::string& desiredOutput); - void ChompedLiteralScalar(std::string& inputScalar, std::string& desiredOutput); - void FoldedScalarWithIndent(std::string& inputScalar, std::string& desiredOutput); - void ColonScalar(std::string& inputScalar, std::string& desiredOutput); - void QuotedScalar(std::string& inputScalar, std::string& desiredOutput); - void CommaScalar(std::string& inputScalar, std::string& desiredOutput); - void DashScalar(std::string& inputScalar, std::string& desiredOutput); - void URLScalar(std::string& inputScalar, std::string& desiredOutput); - - // misc tests - bool SimpleSeq(); - bool SimpleMap(); - bool FlowSeq(); - bool FlowMap(); - bool FlowMapWithOmittedKey(); - bool FlowMapWithOmittedValue(); - bool FlowMapWithSoloEntry(); - bool FlowMapEndingWithSoloEntry(); - bool QuotedSimpleKeys(); - bool CompressedMapAndSeq(); - bool NullBlockSeqEntry(); - bool NullBlockMapKey(); - bool NullBlockMapValue(); - bool SimpleAlias(); - bool AliasWithNull(); - bool AnchorInSimpleKey(); - bool AliasAsSimpleKey(); - bool ExplicitDoc(); - bool MultipleDocs(); - bool ExplicitEndDoc(); - bool MultipleDocsWithSomeExplicitIndicators(); - } -} - -#endif // TESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-reader/tests/aliased.yaml b/yaml-reader/tests/aliased.yaml deleted file mode 100644 index ca79a64..0000000 --- a/yaml-reader/tests/aliased.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- &list -- This document contains a recursive list. -- *list -... From 3d2438368678d35b562b0f58e4e7c6f51ba23b23 Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 27 Oct 2009 14:48:01 +0000 Subject: [PATCH 194/295] Removed unused test yaml file --- test/tests/aliased.yaml | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 test/tests/aliased.yaml diff --git a/test/tests/aliased.yaml b/test/tests/aliased.yaml deleted file mode 100644 index ca79a64..0000000 --- a/test/tests/aliased.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- &list -- This document contains a recursive list. -- *list -... From 4f74f805c256e6151c0958dea3663d408dae2486 Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 27 Oct 2009 14:55:01 +0000 Subject: [PATCH 195/295] Removed crt stuff (we can do memory leak checking in Linux easier) --- include/crt.h | 17 ----------------- include/yaml.h | 1 - src/aliascontent.cpp | 1 - src/content.cpp | 13 ------------- src/content.h | 4 ++-- src/exp.cpp | 1 - src/iterator.cpp | 1 - src/map.cpp | 1 - src/node.cpp | 1 - src/parser.cpp | 1 - src/parserstate.cpp | 1 - src/regex.cpp | 1 - src/scalar.cpp | 1 - src/scanner.cpp | 1 - src/scanscalar.cpp | 1 - src/scantoken.cpp | 1 - src/sequence.cpp | 1 - src/simplekey.cpp | 1 - src/stream.cpp | 1 - test/main.cpp | 4 ---- 20 files changed, 2 insertions(+), 52 deletions(-) delete mode 100644 include/crt.h delete mode 100644 src/content.cpp diff --git a/include/crt.h b/include/crt.h deleted file mode 100644 index 667b60a..0000000 --- a/include/crt.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#ifndef CRT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#define CRT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 - - -// for detecting memory leaks -#ifdef _DEBUG - -#define _CRTDBG_MAP_ALLOC -#include -#include - -#endif // _DEBUG - - -#endif // CRT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml.h b/include/yaml.h index 0f91428..6950ad7 100644 --- a/include/yaml.h +++ b/include/yaml.h @@ -4,7 +4,6 @@ #define YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "crt.h" #include "parser.h" #include "node.h" #include "iterator.h" diff --git a/src/aliascontent.cpp b/src/aliascontent.cpp index aa0f399..305abdc 100644 --- a/src/aliascontent.cpp +++ b/src/aliascontent.cpp @@ -1,4 +1,3 @@ -#include "crt.h" #include "aliascontent.h" namespace YAML diff --git a/src/content.cpp b/src/content.cpp deleted file mode 100644 index 850dcab..0000000 --- a/src/content.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "crt.h" -#include "content.h" - -namespace YAML -{ - Content::Content() - { - } - - Content::~Content() - { - } -} diff --git a/src/content.h b/src/content.h index 71e7037..90e265c 100644 --- a/src/content.h +++ b/src/content.h @@ -23,8 +23,8 @@ namespace YAML class Content { public: - Content(); - virtual ~Content(); + Content() {} + virtual ~Content() {} virtual Content *Clone() const = 0; diff --git a/src/exp.cpp b/src/exp.cpp index 22080c6..8dd3479 100644 --- a/src/exp.cpp +++ b/src/exp.cpp @@ -1,4 +1,3 @@ -#include "crt.h" #include "exp.h" #include "exceptions.h" #include diff --git a/src/iterator.cpp b/src/iterator.cpp index 51e52a3..5d3bc9b 100644 --- a/src/iterator.cpp +++ b/src/iterator.cpp @@ -1,4 +1,3 @@ -#include "crt.h" #include "node.h" #include "exceptions.h" #include "iterpriv.h" diff --git a/src/map.cpp b/src/map.cpp index 6d8873e..4607966 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1,4 +1,3 @@ -#include "crt.h" #include "map.h" #include "node.h" #include "scanner.h" diff --git a/src/node.cpp b/src/node.cpp index c604e43..680729a 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -1,4 +1,3 @@ -#include "crt.h" #include "node.h" #include "token.h" #include "scanner.h" diff --git a/src/parser.cpp b/src/parser.cpp index 1709436..b08a08e 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,4 +1,3 @@ -#include "crt.h" #include "parser.h" #include "scanner.h" #include "token.h" diff --git a/src/parserstate.cpp b/src/parserstate.cpp index 40adb03..8b9531a 100644 --- a/src/parserstate.cpp +++ b/src/parserstate.cpp @@ -1,4 +1,3 @@ -#include "crt.h" #include "parserstate.h" namespace YAML diff --git a/src/regex.cpp b/src/regex.cpp index 7c3f8f5..b35b1f4 100644 --- a/src/regex.cpp +++ b/src/regex.cpp @@ -1,4 +1,3 @@ -#include "crt.h" #include "regex.h" namespace YAML diff --git a/src/scalar.cpp b/src/scalar.cpp index a7ccda9..dbf45b3 100644 --- a/src/scalar.cpp +++ b/src/scalar.cpp @@ -1,4 +1,3 @@ -#include "crt.h" #include "scalar.h" #include "scanner.h" #include "token.h" diff --git a/src/scanner.cpp b/src/scanner.cpp index 552a0cf..725aadc 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -1,4 +1,3 @@ -#include "crt.h" #include "scanner.h" #include "token.h" #include "exceptions.h" diff --git a/src/scanscalar.cpp b/src/scanscalar.cpp index cdbdb60..b3a84cb 100644 --- a/src/scanscalar.cpp +++ b/src/scanscalar.cpp @@ -1,4 +1,3 @@ -#include "crt.h" #include "scanscalar.h" #include "scanner.h" #include "exp.h" diff --git a/src/scantoken.cpp b/src/scantoken.cpp index 80999bd..5bc0c17 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -1,4 +1,3 @@ -#include "crt.h" #include "scanner.h" #include "token.h" #include "exceptions.h" diff --git a/src/sequence.cpp b/src/sequence.cpp index ba38e2c..467826f 100644 --- a/src/sequence.cpp +++ b/src/sequence.cpp @@ -1,4 +1,3 @@ -#include "crt.h" #include "sequence.h" #include "node.h" #include "scanner.h" diff --git a/src/simplekey.cpp b/src/simplekey.cpp index e16dff9..6a605f0 100644 --- a/src/simplekey.cpp +++ b/src/simplekey.cpp @@ -1,4 +1,3 @@ -#include "crt.h" #include "scanner.h" #include "token.h" #include "exceptions.h" diff --git a/src/stream.cpp b/src/stream.cpp index 5cc9ea9..0d1426a 100644 --- a/src/stream.cpp +++ b/src/stream.cpp @@ -1,4 +1,3 @@ -#include "crt.h" #include "stream.h" #include #include "exp.h" diff --git a/test/main.cpp b/test/main.cpp index 881bc57..64c69f1 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -2,10 +2,6 @@ int main() { -#ifdef WINDOWS - _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF); -#endif // WINDOWS Test::RunAll(); - return 0; } From cccbddb54c993672f4afd89b6d48e48935ce797f Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 29 Oct 2009 15:48:06 +0000 Subject: [PATCH 196/295] Merged r295:305 from the tags branch to the trunk --- include/emitter.h | 1 + include/emittermanip.h | 10 + include/exceptions.h | 6 + include/node.h | 5 +- include/parser.h | 10 +- src/emitter.cpp | 39 ++- src/emitterutils.cpp | 18 ++ src/emitterutils.h | 1 + src/exp.h | 5 + src/node.cpp | 15 +- src/parser.cpp | 55 ++-- src/parserstate.cpp | 15 +- {include => src}/parserstate.h | 9 +- src/regex.h | 2 +- src/scanner.cpp | 38 ++- src/scanner.h | 9 +- src/scanscalar.h | 1 + src/scantag.cpp | 84 ++++++ src/scantag.h | 18 ++ src/scantoken.cpp | 52 ++-- src/simplekey.cpp | 13 +- src/stringsource.h | 5 + src/tag.cpp | 50 ++++ src/tag.h | 26 ++ src/token.h | 3 +- test/emittertests.cpp | 171 +++++++++--- test/spectests.cpp | 457 ++++++++++++++++++++++++++++++++- 27 files changed, 973 insertions(+), 145 deletions(-) rename {include => src}/parserstate.h (77%) create mode 100644 src/scantag.cpp create mode 100644 src/scantag.h create mode 100644 src/tag.cpp create mode 100644 src/tag.h diff --git a/include/emitter.h b/include/emitter.h index d512bb8..c13b9cc 100644 --- a/include/emitter.h +++ b/include/emitter.h @@ -52,6 +52,7 @@ namespace YAML Emitter& Write(double d); Emitter& Write(const _Alias& alias); Emitter& Write(const _Anchor& anchor); + Emitter& Write(const _Tag& tag); Emitter& Write(const _Comment& comment); Emitter& Write(const _Null& null); diff --git a/include/emittermanip.h b/include/emittermanip.h index 9284768..c88054f 100644 --- a/include/emittermanip.h +++ b/include/emittermanip.h @@ -80,6 +80,16 @@ namespace YAML inline _Anchor Anchor(const std::string content) { return _Anchor(content); } + + struct _Tag { + _Tag(const std::string& content_): content(content_), verbatim(true) {} + std::string content; + bool verbatim; + }; + + inline _Tag VerbatimTag(const std::string& content) { + return _Tag(content); + } struct _Comment { _Comment(const std::string& content_): content(content_) {} diff --git a/include/exceptions.h b/include/exceptions.h index 8a246f0..2a9c1d1 100644 --- a/include/exceptions.h +++ b/include/exceptions.h @@ -17,7 +17,12 @@ namespace YAML const std::string YAML_DIRECTIVE_ARGS = "YAML directives must have exactly one argument"; const std::string YAML_VERSION = "bad YAML version: "; const std::string YAML_MAJOR_VERSION = "YAML major version too large"; + const std::string REPEATED_YAML_DIRECTIVE= "repeated YAML directive"; const std::string TAG_DIRECTIVE_ARGS = "TAG directives must have exactly two arguments"; + const std::string REPEATED_TAG_DIRECTIVE = "repeated TAG directive"; + const std::string CHAR_IN_TAG_HANDLE = "illegal character found while scanning tag handle"; + const std::string TAG_WITH_NO_SUFFIX = "tag handle with no suffix"; + const std::string END_OF_VERBATIM_TAG = "end of verbatim tag not found"; const std::string END_OF_MAP = "end of map not found"; const std::string END_OF_MAP_FLOW = "end of map flow not found"; const std::string END_OF_SEQ = "end of sequence not found"; @@ -57,6 +62,7 @@ namespace YAML const std::string SINGLE_QUOTED_CHAR = "invalid character in single-quoted string"; const std::string INVALID_ANCHOR = "invalid anchor"; const std::string INVALID_ALIAS = "invalid alias"; + const std::string INVALID_TAG = "invalid tag"; const std::string EXPECTED_KEY_TOKEN = "expected key token"; const std::string EXPECTED_VALUE_TOKEN = "expected value token"; const std::string UNEXPECTED_KEY_TOKEN = "unexpected key token"; diff --git a/include/node.h b/include/node.h index 1503e3b..4218444 100644 --- a/include/node.h +++ b/include/node.h @@ -9,7 +9,6 @@ #include "iterator.h" #include "mark.h" #include "noncopyable.h" -#include "parserstate.h" #include #include #include @@ -21,6 +20,7 @@ namespace YAML class Content; class Scanner; class Emitter; + class ParserState; enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP }; @@ -75,6 +75,9 @@ namespace YAML const Node *Identity() const { return m_pIdentity; } bool IsAlias() const { return m_alias; } bool IsReferenced() const { return m_referenced; } + + // for tags + const std::string GetTag() const { return m_tag; } // TODO: should an aliased node return its alias's tag? // emitting friend Emitter& operator << (Emitter& out, const Node& node); diff --git a/include/parser.h b/include/parser.h index 9f24916..cd61c1c 100644 --- a/include/parser.h +++ b/include/parser.h @@ -5,7 +5,6 @@ #include "node.h" -#include "parserstate.h" #include "noncopyable.h" #include #include @@ -16,6 +15,7 @@ namespace YAML { class Scanner; + class ParserState; struct Token; class Parser: private noncopyable @@ -33,13 +33,13 @@ namespace YAML private: void ParseDirectives(); - void HandleDirective(Token *pToken); - void HandleYamlDirective(Token *pToken); - void HandleTagDirective(Token *pToken); + void HandleDirective(const Token& token); + void HandleYamlDirective(const Token& token); + void HandleTagDirective(const Token& token); private: std::auto_ptr m_pScanner; - ParserState m_state; + std::auto_ptr m_pState; }; } diff --git a/src/emitter.cpp b/src/emitter.cpp index 5eb4bc4..e987ad0 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -146,6 +146,8 @@ namespace YAML switch(curState) { // document-level case ES_WAITING_FOR_DOC: + m_stream << "---"; + m_pState->RequireSeparation(); m_pState->SwitchState(ES_WRITING_DOC); return true; case ES_WRITING_DOC: @@ -323,7 +325,10 @@ namespace YAML EMITTER_STATE curState = m_pState->GetCurState(); EMITTER_MANIP flowType = m_pState->GetFlowType(GT_SEQ); if(flowType == Block) { - if(curState == ES_WRITING_BLOCK_SEQ_ENTRY || curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE) { + if(curState == ES_WRITING_BLOCK_SEQ_ENTRY || + curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE || + curState == ES_WRITING_DOC + ) { m_stream << "\n"; m_pState->UnsetSeparation(); } @@ -354,8 +359,12 @@ namespace YAML // to a flow sequence if it is assert(curState == ES_DONE_WITH_BLOCK_SEQ_ENTRY || curState == ES_WAITING_FOR_BLOCK_SEQ_ENTRY); if(curState == ES_WAITING_FOR_BLOCK_SEQ_ENTRY) { + // Note: only one of these will actually output anything for a given situation + EmitSeparationIfNecessary(); unsigned curIndent = m_pState->GetCurIndent(); - m_stream << IndentTo(curIndent) << "[]"; + m_stream << IndentTo(curIndent); + + m_stream << "[]"; } } else if(flowType == FT_FLOW) { // Note: flow sequences are allowed to be empty @@ -384,7 +393,10 @@ namespace YAML EMITTER_STATE curState = m_pState->GetCurState(); EMITTER_MANIP flowType = m_pState->GetFlowType(GT_MAP); if(flowType == Block) { - if(curState == ES_WRITING_BLOCK_SEQ_ENTRY || curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE) { + if(curState == ES_WRITING_BLOCK_SEQ_ENTRY || + curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE || + curState == ES_WRITING_DOC + ) { m_stream << "\n"; m_pState->UnsetSeparation(); } @@ -415,8 +427,11 @@ namespace YAML // to a flow sequence if it is assert(curState == ES_DONE_WITH_BLOCK_MAP_VALUE || curState == ES_WAITING_FOR_BLOCK_MAP_ENTRY); if(curState == ES_WAITING_FOR_BLOCK_MAP_ENTRY) { + // Note: only one of these will actually output anything for a given situation + EmitSeparationIfNecessary(); unsigned curIndent = m_pState->GetCurIndent(); - m_stream << IndentTo(curIndent) << "{}"; + m_stream << IndentTo(curIndent); + m_stream << "{}"; } } else if(flowType == FT_FLOW) { // Note: flow maps are allowed to be empty @@ -675,6 +690,22 @@ namespace YAML return *this; } + Emitter& Emitter::Write(const _Tag& tag) + { + if(!good()) + return *this; + + PreAtomicWrite(); + EmitSeparationIfNecessary(); + if(!Utils::WriteTag(m_stream, tag.content)) { + m_pState->SetError(ErrorMsg::INVALID_TAG); + return *this; + } + m_pState->RequireSeparation(); + // Note: no PostAtomicWrite() because we need another value for this node + return *this; + } + Emitter& Emitter::Write(const _Comment& comment) { if(!good()) diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index 837ae20..202750a 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -293,6 +293,24 @@ namespace YAML out << "&"; return WriteAliasName(out, str); } + + bool WriteTag(ostream& out, const std::string& str) + { + out << "!<"; + StringCharSource buffer(str.c_str(), str.size()); + while(buffer) { + int n = Exp::URI.Match(buffer); + if(n <= 0) + return false; + + while(--n >= 0) { + out << buffer[0]; + ++buffer; + } + } + out << ">"; + return true; + } } } diff --git a/src/emitterutils.h b/src/emitterutils.h index b7fa346..7ceb6ff 100644 --- a/src/emitterutils.h +++ b/src/emitterutils.h @@ -18,6 +18,7 @@ namespace YAML bool WriteComment(ostream& out, const std::string& str, int postCommentIndent); bool WriteAlias(ostream& out, const std::string& str); bool WriteAnchor(ostream& out, const std::string& str); + bool WriteTag(ostream& out, const std::string& str); } } diff --git a/src/exp.h b/src/exp.h index 126c2c9..c84f12a 100644 --- a/src/exp.h +++ b/src/exp.h @@ -25,6 +25,7 @@ namespace YAML const RegEx Digit = RegEx('0', '9'); const RegEx Alpha = RegEx('a', 'z') || RegEx('A', 'Z'); const RegEx AlphaNumeric = Alpha || Digit; + const RegEx Word = AlphaNumeric || RegEx('-'); const RegEx Hex = Digit || RegEx('A', 'F') || RegEx('a', 'f'); // Valid Unicode code points that are not part of c-printable (YAML 1.2, sec. 5.1) const RegEx NotPrintable = RegEx(0) || @@ -45,6 +46,8 @@ namespace YAML ValueInFlow = RegEx(':') + (BlankOrBreak || RegEx(",}", REGEX_OR)); const RegEx Comment = RegEx('#'); const RegEx AnchorEnd = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak; + const RegEx URI = Word || RegEx("#;/?:@&=+$,_.!~*'()[]", REGEX_OR) || (RegEx('%') + Hex + Hex); + const RegEx Tag = Word || RegEx("#;/?:@&=+$_.~*'", REGEX_OR) || (RegEx('%') + Hex + Hex); // Plain scalar rules: // . Cannot start with a blank. @@ -79,6 +82,8 @@ namespace YAML const char Tag = '!'; const char LiteralScalar = '|'; const char FoldedScalar = '>'; + const char VerbatimTagStart = '<'; + const char VerbatimTagEnd = '>'; } } diff --git a/src/node.cpp b/src/node.cpp index 680729a..178377f 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -9,6 +9,7 @@ #include "aliascontent.h" #include "iterpriv.h" #include "emitter.h" +#include "tag.h" #include namespace YAML @@ -137,10 +138,8 @@ namespace YAML if(m_tag != "") throw ParserException(token.mark, ErrorMsg::MULTIPLE_TAGS); - m_tag = state.TranslateTag(token.value); - - for(std::size_t i=0;ipop(); } @@ -241,7 +240,10 @@ namespace YAML bool Node::GetScalar(std::string& s) const { if(!m_pContent) { - s = "~"; + if(m_tag.empty()) + s = "~"; + else + s = ""; return true; } @@ -258,7 +260,8 @@ namespace YAML out << Anchor(node.m_anchor); } - // TODO: write tag + if(node.m_tag != "") + out << VerbatimTag(node.m_tag); // write content if(node.m_pContent) diff --git a/src/parser.cpp b/src/parser.cpp index b08a08e..e9fd0a1 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2,6 +2,7 @@ #include "scanner.h" #include "token.h" #include "exceptions.h" +#include "parserstate.h" #include #include @@ -28,7 +29,7 @@ namespace YAML void Parser::Load(std::istream& in) { m_pScanner.reset(new Scanner(in)); - m_state.Reset(); + m_pState.reset(new ParserState); } // GetNextDocument @@ -54,7 +55,7 @@ namespace YAML m_pScanner->pop(); // now parse our root node - document.Parse(m_pScanner.get(), m_state); + 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) @@ -83,51 +84,59 @@ 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_state.Reset(); + m_pState.reset(new ParserState); readDirective = true; - HandleDirective(&token); + HandleDirective(token); m_pScanner->pop(); } } - void Parser::HandleDirective(Token *pToken) + void Parser::HandleDirective(const Token& token) { - if(pToken->value == "YAML") - HandleYamlDirective(pToken); - else if(pToken->value == "TAG") - HandleTagDirective(pToken); + if(token.value == "YAML") + HandleYamlDirective(token); + else if(token.value == "TAG") + HandleTagDirective(token); } // HandleYamlDirective // . Should be of the form 'major.minor' (like a version number) - void Parser::HandleYamlDirective(Token *pToken) + void Parser::HandleYamlDirective(const Token& token) { - if(pToken->params.size() != 1) - throw ParserException(pToken->mark, ErrorMsg::YAML_DIRECTIVE_ARGS); + if(token.params.size() != 1) + throw ParserException(token.mark, ErrorMsg::YAML_DIRECTIVE_ARGS); + + if(!m_pState->version.isDefault) + throw ParserException(token.mark, ErrorMsg::REPEATED_YAML_DIRECTIVE); - std::stringstream str(pToken->params[0]); - str >> m_state.version.major; + std::stringstream str(token.params[0]); + str >> m_pState->version.major; str.get(); - str >> m_state.version.minor; + str >> m_pState->version.minor; if(!str || str.peek() != EOF) - throw ParserException(pToken->mark, ErrorMsg::YAML_VERSION + pToken->params[0]); + throw ParserException(token.mark, ErrorMsg::YAML_VERSION + token.params[0]); - if(m_state.version.major > 1) - throw ParserException(pToken->mark, ErrorMsg::YAML_MAJOR_VERSION); + if(m_pState->version.major > 1) + throw ParserException(token.mark, ErrorMsg::YAML_MAJOR_VERSION); + m_pState->version.isDefault = false; // TODO: warning on major == 1, minor > 2? } // HandleTagDirective // . Should be of the form 'handle prefix', where 'handle' is converted to 'prefix' in the file. - void Parser::HandleTagDirective(Token *pToken) + void Parser::HandleTagDirective(const Token& token) { - if(pToken->params.size() != 2) - throw ParserException(pToken->mark, ErrorMsg::TAG_DIRECTIVE_ARGS); + if(token.params.size() != 2) + throw ParserException(token.mark, ErrorMsg::TAG_DIRECTIVE_ARGS); - std::string handle = pToken->params[0], prefix = pToken->params[1]; - m_state.tags[handle] = prefix; + const std::string& handle = token.params[0]; + const std::string& prefix = token.params[1]; + if(m_pState->tags.find(handle) != m_pState->tags.end()) + throw ParserException(token.mark, ErrorMsg::REPEATED_TAG_DIRECTIVE); + + m_pState->tags[handle] = prefix; } void Parser::PrintTokens(std::ostream& out) diff --git a/src/parserstate.cpp b/src/parserstate.cpp index 8b9531a..ebd6609 100644 --- a/src/parserstate.cpp +++ b/src/parserstate.cpp @@ -2,23 +2,22 @@ namespace YAML { - void ParserState::Reset() + ParserState::ParserState() { // version + version.isDefault = true; version.major = 1; version.minor = 2; - - // and tags - tags.clear(); - tags["!"] = "!"; - tags["!!"] = "tag:yaml.org,2002:"; } - std::string ParserState::TranslateTag(const std::string& handle) const + const std::string ParserState::TranslateTagHandle(const std::string& handle) const { std::map ::const_iterator it = tags.find(handle); - if(it == tags.end()) + if(it == tags.end()) { + if(handle == "!!") + return "tag:yaml.org,2002:"; return handle; + } return it->second; } diff --git a/include/parserstate.h b/src/parserstate.h similarity index 77% rename from include/parserstate.h rename to src/parserstate.h index 1f27a7f..09b4afd 100644 --- a/include/parserstate.h +++ b/src/parserstate.h @@ -10,16 +10,17 @@ namespace YAML { struct Version { + bool isDefault; int major, minor; }; - + struct ParserState { + ParserState(); + const std::string TranslateTagHandle(const std::string& handle) const; + Version version; std::map tags; - - void Reset(); - std::string TranslateTag(const std::string& handle) const; }; } diff --git a/src/regex.h b/src/regex.h index 59a4833..12d9be7 100644 --- a/src/regex.h +++ b/src/regex.h @@ -37,12 +37,12 @@ namespace YAML int Match(const std::string& str) const; int Match(const Stream& in) const; + template int Match(const Source& source) const; private: RegEx(REGEX_OP op); template bool IsValidSource(const Source& source) const; - template int Match(const Source& source) const; template int MatchUnchecked(const Source& source) const; template int MatchOpEmpty(const Source& source) const; diff --git a/src/scanner.cpp b/src/scanner.cpp index 725aadc..877c404 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -3,6 +3,7 @@ #include "exceptions.h" #include "exp.h" #include +#include namespace YAML { @@ -13,6 +14,9 @@ namespace YAML Scanner::~Scanner() { + for(unsigned i=0;i pIndent(new IndentMarker(column, type)); + IndentMarker& indent = *pIndent; + const IndentMarker& lastIndent = *m_indents.top(); // is this actually an indentation? if(indent.column < lastIndent.column) @@ -276,13 +283,15 @@ namespace YAML indent.pStartToken = &m_tokens.back(); // and then the indent - m_indents.push(indent); - return &m_indents.top(); + m_indents.push(&indent); + m_indentRefs.push_back(pIndent.release()); + return m_indentRefs.back(); } // PopIndentToHere // . Pops indentations off the stack until we reach the current indentation level, // and enqueues the proper token each time. + // . Then pops all invalid indentations off. void Scanner::PopIndentToHere() { // are we in flow? @@ -291,7 +300,7 @@ namespace YAML // now pop away while(!m_indents.empty()) { - const IndentMarker& indent = m_indents.top(); + const IndentMarker& indent = *m_indents.top(); if(indent.column < INPUT.column()) break; if(indent.column == INPUT.column() && !(indent.type == IndentMarker::SEQ && !Exp::BlockEntry.Matches(INPUT))) @@ -299,6 +308,9 @@ namespace YAML PopIndent(); } + + while(!m_indents.empty() && m_indents.top()->status == IndentMarker::INVALID) + PopIndent(); } // PopAllIndents @@ -312,7 +324,7 @@ namespace YAML // now pop away while(!m_indents.empty()) { - const IndentMarker& indent = m_indents.top(); + const IndentMarker& indent = *m_indents.top(); if(indent.type == IndentMarker::NONE) break; @@ -324,17 +336,17 @@ namespace YAML // . Pops a single indent, pushing the proper token void Scanner::PopIndent() { - IndentMarker indent = m_indents.top(); - IndentMarker::INDENT_TYPE type = indent.type; + const IndentMarker& indent = *m_indents.top(); m_indents.pop(); - if(!indent.isValid) { + + if(indent.status != IndentMarker::VALID) { InvalidateSimpleKey(); return; } - if(type == IndentMarker::SEQ) + if(indent.type == IndentMarker::SEQ) m_tokens.push(Token(Token::BLOCK_SEQ_END, INPUT.mark())); - else if(type == IndentMarker::MAP) + else if(indent.type == IndentMarker::MAP) m_tokens.push(Token(Token::BLOCK_MAP_END, INPUT.mark())); } @@ -343,7 +355,7 @@ namespace YAML { if(m_indents.empty()) return 0; - return m_indents.top().column; + return m_indents.top()->column; } // Save diff --git a/src/scanner.h b/src/scanner.h index 19ee048..ddae0de 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -36,11 +36,12 @@ namespace YAML private: struct IndentMarker { enum INDENT_TYPE { MAP, SEQ, NONE }; - IndentMarker(int column_, INDENT_TYPE type_): column(column_), type(type_), isValid(true), pStartToken(0) {} + enum STATUS { VALID, INVALID, UNKNOWN }; + IndentMarker(int column_, INDENT_TYPE type_): column(column_), type(type_), status(VALID), pStartToken(0) {} int column; INDENT_TYPE type; - bool isValid; + STATUS status; Token *pStartToken; }; @@ -118,10 +119,12 @@ namespace YAML bool m_startedStream, m_endedStream; bool m_simpleKeyAllowed; std::stack m_simpleKeys; - std::stack m_indents; + std::stack m_indents; + std::vector m_indentRefs; // for "garbage collection" std::stack m_flows; std::map m_anchors; }; } #endif // SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + diff --git a/src/scanscalar.h b/src/scanscalar.h index 6f6f559..1f92b9e 100644 --- a/src/scanscalar.h +++ b/src/scanscalar.h @@ -40,3 +40,4 @@ namespace YAML } #endif // SCANSCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + diff --git a/src/scantag.cpp b/src/scantag.cpp new file mode 100644 index 0000000..17a6d65 --- /dev/null +++ b/src/scantag.cpp @@ -0,0 +1,84 @@ +#include "scanner.h" +#include "regex.h" +#include "exp.h" +#include "exceptions.h" + +namespace YAML +{ + const std::string ScanVerbatimTag(Stream& INPUT) + { + std::string tag; + + // eat the start character + INPUT.get(); + + while(INPUT) { + if(INPUT.peek() == Keys::VerbatimTagEnd) { + // eat the end character + INPUT.get(); + return tag; + } + + int n = Exp::URI.Match(INPUT); + if(n <= 0) + break; + + tag += INPUT.get(n); + } + + throw ParserException(INPUT.mark(), ErrorMsg::END_OF_VERBATIM_TAG); + } + + const std::string ScanTagHandle(Stream& INPUT, bool& canBeHandle) + { + std::string tag; + canBeHandle = true; + Mark firstNonWordChar; + + while(INPUT) { + if(INPUT.peek() == Keys::Tag) { + if(!canBeHandle) + throw ParserException(firstNonWordChar, ErrorMsg::CHAR_IN_TAG_HANDLE); + break; + } + + int n = 0; + if(canBeHandle) { + n = Exp::Word.Match(INPUT); + if(n <= 0) { + canBeHandle = false; + firstNonWordChar = INPUT.mark(); + } + } + + if(!canBeHandle) + n = Exp::Tag.Match(INPUT); + + if(n <= 0) + break; + + tag += INPUT.get(n); + } + + return tag; + } + + const std::string ScanTagSuffix(Stream& INPUT) + { + std::string tag; + + while(INPUT) { + int n = Exp::Tag.Match(INPUT); + if(n <= 0) + break; + + tag += INPUT.get(n); + } + + if(tag.empty()) + throw ParserException(INPUT.mark(), ErrorMsg::TAG_WITH_NO_SUFFIX); + + return tag; + } +} + diff --git a/src/scantag.h b/src/scantag.h new file mode 100644 index 0000000..77b315d --- /dev/null +++ b/src/scantag.h @@ -0,0 +1,18 @@ +#pragma once + +#ifndef SCANTAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define SCANTAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + +#include +#include "stream.h" + +namespace YAML +{ + const std::string ScanVerbatimTag(Stream& INPUT); + const std::string ScanTagHandle(Stream& INPUT, bool& canBeHandle); + const std::string ScanTagSuffix(Stream& INPUT); +} + +#endif // SCANTAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + diff --git a/src/scantoken.cpp b/src/scantoken.cpp index 5bc0c17..c1551ac 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -3,6 +3,8 @@ #include "exceptions.h" #include "exp.h" #include "scanscalar.h" +#include "scantag.h" +#include "tag.h" #include namespace YAML @@ -24,12 +26,12 @@ namespace YAML m_simpleKeyAllowed = false; // store pos and eat indicator - Mark mark = INPUT.mark(); + Token token(Token::DIRECTIVE, INPUT.mark()); INPUT.eat(1); // read name while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) - name += INPUT.get(); + token.value += INPUT.get(); // read parameters while(1) { @@ -46,12 +48,9 @@ namespace YAML while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) param += INPUT.get(); - params.push_back(param); + token.params.push_back(param); } - Token token(Token::DIRECTIVE, mark); - token.value = name; - token.params = params; m_tokens.push(token); } @@ -242,37 +241,34 @@ namespace YAML // Tag void Scanner::ScanTag() { - std::string handle, suffix; - // insert a potential simple key InsertPotentialSimpleKey(); m_simpleKeyAllowed = false; + Token token(Token::TAG, INPUT.mark()); + // eat the indicator - Mark mark = INPUT.mark(); - handle += INPUT.get(); + INPUT.get(); + + if(INPUT && INPUT.peek() == Keys::VerbatimTagStart){ + std::string tag = ScanVerbatimTag(INPUT); - // read the handle - while(INPUT && INPUT.peek() != Keys::Tag && !Exp::BlankOrBreak.Matches(INPUT)) - handle += INPUT.get(); - - // is there a suffix? - if(INPUT.peek() == Keys::Tag) { - // eat the indicator - handle += INPUT.get(); - - // then read it - while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) - suffix += INPUT.get(); + token.value = tag; + token.data = Tag::VERBATIM; } else { - // this is a bit weird: we keep just the '!' as the handle and move the rest to the suffix - suffix = handle.substr(1); - handle = "!"; + bool canBeHandle; + token.value = ScanTagHandle(INPUT, canBeHandle); + token.data = (token.value.empty() ? Tag::SECONDARY_HANDLE : Tag::PRIMARY_HANDLE); + + // is there a suffix? + if(canBeHandle && INPUT.peek() == Keys::Tag) { + // eat the indicator + INPUT.get(); + token.params.push_back(ScanTagSuffix(INPUT)); + token.data = Tag::NAMED_HANDLE; + } } - Token token(Token::TAG, mark); - token.value = handle; - token.params.push_back(suffix); m_tokens.push(token); } diff --git a/src/simplekey.cpp b/src/simplekey.cpp index 6a605f0..f99cea6 100644 --- a/src/simplekey.cpp +++ b/src/simplekey.cpp @@ -12,9 +12,11 @@ namespace YAML void Scanner::SimpleKey::Validate() { - // Note: pIndent will *not* be garbage here; see below + // Note: pIndent will *not* be garbage here; + // we "garbage collect" them so we can + // always refer to them if(pIndent) - pIndent->isValid = true; + pIndent->status = IndentMarker::VALID; if(pMapStart) pMapStart->status = Token::VALID; if(pKey) @@ -23,8 +25,8 @@ namespace YAML void Scanner::SimpleKey::Invalidate() { - // Note: pIndent might be a garbage pointer here, but that's ok - // An indent will only be popped if the simple key is invalid + if(pIndent) + pIndent->status = IndentMarker::INVALID; if(pMapStart) pMapStart->status = Token::INVALID; if(pKey) @@ -68,7 +70,7 @@ namespace YAML // first add a map start, if necessary key.pIndent = PushIndentTo(INPUT.column(), IndentMarker::MAP); if(key.pIndent) { - key.pIndent->isValid = false; + key.pIndent->status = IndentMarker::UNKNOWN; key.pMapStart = key.pIndent->pStartToken; key.pMapStart->status = Token::UNVERIFIED; } @@ -135,3 +137,4 @@ namespace YAML m_simpleKeys.pop(); } } + diff --git a/src/stringsource.h b/src/stringsource.h index c4e4c13..20d56ae 100644 --- a/src/stringsource.h +++ b/src/stringsource.h @@ -30,6 +30,11 @@ namespace YAML ++m_offset; return *this; } + + StringCharSource& operator += (std::size_t offset) { + m_offset += offset; + return *this; + } private: const char *m_str; std::size_t m_size; diff --git a/src/tag.cpp b/src/tag.cpp new file mode 100644 index 0000000..694a4f3 --- /dev/null +++ b/src/tag.cpp @@ -0,0 +1,50 @@ +#include "tag.h" +#include "token.h" +#include "parserstate.h" +#include + +namespace YAML +{ + Tag::Tag(const Token& token): type(static_cast(token.data)) + { + switch(type) { + case VERBATIM: + value = token.value; + break; + case PRIMARY_HANDLE: + value = token.value; + break; + case SECONDARY_HANDLE: + value = token.value; + break; + case NAMED_HANDLE: + handle = token.value; + value = token.params[0]; + break; + case NON_SPECIFIC: + break; + default: + assert(false); + } + } + + const std::string Tag::Translate(const ParserState& state) + { + switch(type) { + case VERBATIM: + return value; + case PRIMARY_HANDLE: + return state.TranslateTagHandle("!") + value; + case SECONDARY_HANDLE: + return state.TranslateTagHandle("!!") + value; + case NAMED_HANDLE: + return state.TranslateTagHandle("!" + handle + "!") + value; + case NON_SPECIFIC: + // TODO: + return "!"; + default: + assert(false); + } + } +} + diff --git a/src/tag.h b/src/tag.h new file mode 100644 index 0000000..b448994 --- /dev/null +++ b/src/tag.h @@ -0,0 +1,26 @@ +#pragma once + +#ifndef TAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define TAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#include + +namespace YAML +{ + struct Token; + struct ParserState; + + struct Tag { + enum TYPE { + VERBATIM, PRIMARY_HANDLE, SECONDARY_HANDLE, NAMED_HANDLE, NON_SPECIFIC + }; + + Tag(const Token& token); + const std::string Translate(const ParserState& state); + + TYPE type; + std::string handle, value; + }; +} + +#endif // TAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/token.h b/src/token.h index 8ab82d5..ff1a457 100644 --- a/src/token.h +++ b/src/token.h @@ -59,7 +59,7 @@ namespace YAML }; // data - Token(TYPE type_, const Mark& mark_): status(VALID), type(type_), mark(mark_) {} + Token(TYPE type_, const Mark& mark_): status(VALID), type(type_), mark(mark_), data(0) {} friend std::ostream& operator << (std::ostream& out, const Token& token) { out << TokenNames[token.type] << std::string(": ") << token.value; @@ -73,6 +73,7 @@ namespace YAML Mark mark; std::string value; std::vector params; + int data; }; } diff --git a/test/emittertests.cpp b/test/emittertests.cpp index f85af8d..fa0ef5c 100644 --- a/test/emittertests.cpp +++ b/test/emittertests.cpp @@ -9,7 +9,7 @@ namespace Test void SimpleScalar(YAML::Emitter& out, std::string& desiredOutput) { out << "Hello, World!"; - desiredOutput = "Hello, World!"; + desiredOutput = "--- Hello, World!"; } void SimpleSeq(YAML::Emitter& out, std::string& desiredOutput) { @@ -19,7 +19,7 @@ namespace Test out << "milk"; out << YAML::EndSeq; - desiredOutput = "- eggs\n- bread\n- milk"; + desiredOutput = "---\n- eggs\n- bread\n- milk"; } void SimpleFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { @@ -30,7 +30,7 @@ namespace Test out << "Moe"; out << YAML::EndSeq; - desiredOutput = "[Larry, Curly, Moe]"; + desiredOutput = "--- [Larry, Curly, Moe]"; } void EmptyFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { @@ -38,7 +38,7 @@ namespace Test out << YAML::BeginSeq; out << YAML::EndSeq; - desiredOutput = "[]"; + desiredOutput = "--- []"; } void NestedBlockSeq(YAML::Emitter& out, std::string& desiredOutput) { @@ -47,7 +47,7 @@ namespace Test out << YAML::BeginSeq << "subitem 1" << "subitem 2" << YAML::EndSeq; out << YAML::EndSeq; - desiredOutput = "- item 1\n-\n - subitem 1\n - subitem 2"; + desiredOutput = "---\n- item 1\n-\n - subitem 1\n - subitem 2"; } void NestedFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { @@ -56,7 +56,7 @@ namespace Test out << YAML::Flow << YAML::BeginSeq << "two" << "three" << YAML::EndSeq; out << YAML::EndSeq; - desiredOutput = "- one\n- [two, three]"; + desiredOutput = "---\n- one\n- [two, three]"; } void SimpleMap(YAML::Emitter& out, std::string& desiredOutput) { @@ -67,7 +67,7 @@ namespace Test out << YAML::Value << "3B"; out << YAML::EndMap; - desiredOutput = "name: Ryan Braun\nposition: 3B"; + desiredOutput = "---\nname: Ryan Braun\nposition: 3B"; } void SimpleFlowMap(YAML::Emitter& out, std::string& desiredOutput) { @@ -79,7 +79,7 @@ namespace Test out << YAML::Value << "blue"; out << YAML::EndMap; - desiredOutput = "{shape: square, color: blue}"; + desiredOutput = "--- {shape: square, color: blue}"; } void MapAndList(YAML::Emitter& out, std::string& desiredOutput) { @@ -90,7 +90,7 @@ namespace Test out << YAML::Value << YAML::BeginSeq << "Sasha" << "Malia" << YAML::EndSeq; out << YAML::EndMap; - desiredOutput = "name: Barack Obama\nchildren:\n - Sasha\n - Malia"; + desiredOutput = "---\nname: Barack Obama\nchildren:\n - Sasha\n - Malia"; } void ListAndMap(YAML::Emitter& out, std::string& desiredOutput) { @@ -103,7 +103,7 @@ namespace Test out << "item 2"; out << YAML::EndSeq; - desiredOutput = "- item 1\n-\n pens: 8\n pencils: 14\n- item 2"; + desiredOutput = "---\n- item 1\n-\n pens: 8\n pencils: 14\n- item 2"; } void NestedBlockMap(YAML::Emitter& out, std::string& desiredOutput) { @@ -119,7 +119,7 @@ namespace Test out << YAML::EndMap; out << YAML::EndMap; - desiredOutput = "name: Fred\ngrades:\n algebra: A\n physics: C+\n literature: B"; + desiredOutput = "---\nname: Fred\ngrades:\n algebra: A\n physics: C+\n literature: B"; } void NestedFlowMap(YAML::Emitter& out, std::string& desiredOutput) { @@ -136,7 +136,7 @@ namespace Test out << YAML::EndMap; out << YAML::EndMap; - desiredOutput = "{name: Fred, grades: {algebra: A, physics: C+, literature: B}}"; + desiredOutput = "--- {name: Fred, grades: {algebra: A, physics: C+, literature: B}}"; } void MapListMix(YAML::Emitter& out, std::string& desiredOutput) { @@ -149,7 +149,7 @@ namespace Test out << YAML::Key << "invincible" << YAML::Value << YAML::OnOffBool << false; out << YAML::EndMap; - desiredOutput = "name: Bob\nposition: [2, 4]\ninvincible: off"; + desiredOutput = "---\nname: Bob\nposition: [2, 4]\ninvincible: off"; } void SimpleLongKey(YAML::Emitter& out, std::string& desiredOutput) @@ -162,7 +162,7 @@ namespace Test out << YAML::Value << 145; out << YAML::EndMap; - desiredOutput = "? height\n: 5'9\"\n? weight\n: 145"; + desiredOutput = "---\n? height\n: 5'9\"\n? weight\n: 145"; } void SingleLongKey(YAML::Emitter& out, std::string& desiredOutput) @@ -176,7 +176,7 @@ namespace Test out << YAML::Value << 145; out << YAML::EndMap; - desiredOutput = "age: 24\n? height\n: 5'9\"\nweight: 145"; + desiredOutput = "---\nage: 24\n? height\n: 5'9\"\nweight: 145"; } void ComplexLongKey(YAML::Emitter& out, std::string& desiredOutput) @@ -189,7 +189,7 @@ namespace Test out << YAML::Value << "demon"; out << YAML::EndMap; - desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon"; + desiredOutput = "---\n?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon"; } void AutoLongKey(YAML::Emitter& out, std::string& desiredOutput) @@ -203,7 +203,7 @@ namespace Test out << YAML::Value << "angel"; out << YAML::EndMap; - desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon\nthe origin: angel"; + desiredOutput = "---\n?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon\nthe origin: angel"; } void ScalarFormat(YAML::Emitter& out, std::string& desiredOutput) @@ -217,7 +217,7 @@ namespace Test out << YAML::Literal << "literal scalar\nthat may span\nmany, many\nlines and have \"whatever\" crazy\tsymbols that we like"; out << YAML::EndSeq; - desiredOutput = "- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\x0adouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like"; + desiredOutput = "---\n- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\x0adouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like"; } void AutoLongKeyScalar(YAML::Emitter& out, std::string& desiredOutput) @@ -227,7 +227,7 @@ namespace Test out << YAML::Value << "and its value"; out << YAML::EndMap; - desiredOutput = "? |\n multi-line\n scalar\n: and its value"; + desiredOutput = "---\n? |\n multi-line\n scalar\n: and its value"; } void LongKeyFlowMap(YAML::Emitter& out, std::string& desiredOutput) @@ -240,7 +240,7 @@ namespace Test out << YAML::Value << "and its value"; out << YAML::EndMap; - desiredOutput = "{simple key: and value, ? long key: and its value}"; + desiredOutput = "--- {simple key: and value, ? long key: and its value}"; } void BlockMapAsKey(YAML::Emitter& out, std::string& desiredOutput) @@ -255,7 +255,7 @@ namespace Test out << "total value"; out << YAML::EndMap; - desiredOutput = "?\n key: value\n next key: next value\n: total value"; + desiredOutput = "---\n?\n key: value\n next key: next value\n: total value"; } void AliasAndAnchor(YAML::Emitter& out, std::string& desiredOutput) @@ -269,7 +269,7 @@ namespace Test out << YAML::Alias("fred"); out << YAML::EndSeq; - desiredOutput = "- &fred\n name: Fred\n age: 42\n- *fred"; + desiredOutput = "---\n- &fred\n name: Fred\n age: 42\n- *fred"; } void AliasAndAnchorWithNull(YAML::Emitter& out, std::string& desiredOutput) @@ -279,7 +279,98 @@ namespace Test out << YAML::Alias("fred"); out << YAML::EndSeq; - desiredOutput = "- &fred ~\n- *fred"; + desiredOutput = "---\n- &fred ~\n- *fred"; + } + + void SimpleVerbatimTag(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::VerbatimTag("!foo") << "bar"; + + desiredOutput = "--- ! bar"; + } + + void VerbatimTagInBlockSeq(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << YAML::VerbatimTag("!foo") << "bar"; + out << "baz"; + out << YAML::EndSeq; + + desiredOutput = "---\n- ! bar\n- baz"; + } + + void VerbatimTagInFlowSeq(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Flow << YAML::BeginSeq; + out << YAML::VerbatimTag("!foo") << "bar"; + out << "baz"; + out << YAML::EndSeq; + + desiredOutput = "--- [! bar, baz]"; + } + + void VerbatimTagInFlowSeqWithNull(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Flow << YAML::BeginSeq; + out << YAML::VerbatimTag("!foo") << YAML::Null; + out << "baz"; + out << YAML::EndSeq; + + desiredOutput = "--- [! ~, baz]"; + } + + void VerbatimTagInBlockMap(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << YAML::VerbatimTag("!foo") << "bar"; + out << YAML::Value << YAML::VerbatimTag("!waz") << "baz"; + out << YAML::EndMap; + + desiredOutput = "---\n! bar: ! baz"; + } + + void VerbatimTagInFlowMap(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Flow << YAML::BeginMap; + out << YAML::Key << YAML::VerbatimTag("!foo") << "bar"; + out << YAML::Value << "baz"; + out << YAML::EndMap; + + desiredOutput = "--- {! bar: baz}"; + } + + void VerbatimTagInFlowMapWithNull(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Flow << YAML::BeginMap; + out << YAML::Key << YAML::VerbatimTag("!foo") << YAML::Null; + out << YAML::Value << "baz"; + out << YAML::EndMap; + + desiredOutput = "--- {! ~: baz}"; + } + + void VerbatimTagWithEmptySeq(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::VerbatimTag("!foo") << YAML::BeginSeq << YAML::EndSeq; + + desiredOutput = "--- !\n[]"; + } + + void VerbatimTagWithEmptyMap(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::VerbatimTag("!bar") << YAML::BeginMap << YAML::EndMap; + + desiredOutput = "--- !\n{}"; + } + + void VerbatimTagWithEmptySeqAndMap(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << YAML::VerbatimTag("!foo") << YAML::BeginSeq << YAML::EndSeq; + out << YAML::VerbatimTag("!bar") << YAML::BeginMap << YAML::EndMap; + out << YAML::EndSeq; + + desiredOutput = "---\n- !\n []\n- !\n {}"; } void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput) @@ -335,7 +426,7 @@ namespace Test out << YAML::Value << YAML::Alias("id001"); out << YAML::EndMap; - desiredOutput = "receipt: Oz-Ware Purchase Invoice\ndate: 2007-08-06\ncustomer:\n given: Dorothy\n family: Gale\nitems:\n -\n part_no: A4786\n descrip: Water Bucket (Filled)\n price: 1.47\n quantity: 4\n -\n part_no: E1628\n descrip: High Heeled \"Ruby\" Slippers\n price: 100.27\n quantity: 1\nbill-to: &id001\n street: |\n 123 Tornado Alley\n Suite 16\n city: East Westville\n state: KS\nship-to: *id001"; + desiredOutput = "---\nreceipt: Oz-Ware Purchase Invoice\ndate: 2007-08-06\ncustomer:\n given: Dorothy\n family: Gale\nitems:\n -\n part_no: A4786\n descrip: Water Bucket (Filled)\n price: 1.47\n quantity: 4\n -\n part_no: E1628\n descrip: High Heeled \"Ruby\" Slippers\n price: 100.27\n quantity: 1\nbill-to: &id001\n street: |\n 123 Tornado Alley\n Suite 16\n city: East Westville\n state: KS\nship-to: *id001"; } void STLContainers(YAML::Emitter& out, std::string& desiredOutput) @@ -355,7 +446,7 @@ namespace Test out << ages; out << YAML::EndSeq; - desiredOutput = "- [2, 3, 5, 7, 11, 13]\n-\n Daniel: 26\n Jesse: 24"; + desiredOutput = "---\n- [2, 3, 5, 7, 11, 13]\n-\n Daniel: 26\n Jesse: 24"; } void SimpleComment(YAML::Emitter& out, std::string& desiredOutput) @@ -365,7 +456,7 @@ namespace Test out << YAML::Value << "least squares" << YAML::Comment("should we change this method?"); out << YAML::EndMap; - desiredOutput = "method: least squares # should we change this method?"; + desiredOutput = "---\nmethod: least squares # should we change this method?"; } void MultiLineComment(YAML::Emitter& out, std::string& desiredOutput) @@ -375,7 +466,7 @@ namespace Test out << "item 2"; out << YAML::EndSeq; - desiredOutput = "- item 1 # really really long\n # comment that couldn't possibly\n # fit on one line\n- item 2"; + desiredOutput = "---\n- item 1 # really really long\n # comment that couldn't possibly\n # fit on one line\n- item 2"; } void ComplexComments(YAML::Emitter& out, std::string& desiredOutput) @@ -385,7 +476,7 @@ namespace Test out << YAML::Value << "value"; out << YAML::EndMap; - desiredOutput = "? long key # long key\n: value"; + desiredOutput = "---\n? long key # long key\n: value"; } void Indentation(YAML::Emitter& out, std::string& desiredOutput) @@ -398,7 +489,7 @@ namespace Test out << YAML::EndMap; out << YAML::EndSeq; - desiredOutput = "-\n key 1: value 1\n key 2:\n - a\n - b\n - c"; + desiredOutput = "---\n-\n key 1: value 1\n key 2:\n - a\n - b\n - c"; } void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) @@ -413,7 +504,7 @@ namespace Test out << YAML::EndMap; out << YAML::EndSeq; - desiredOutput = "-\n ? key 1\n : value 1\n ? key 2\n : [a, b, c]"; + desiredOutput = "---\n-\n ? key 1\n : value 1\n ? key 2\n : [a, b, c]"; } void ComplexGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) @@ -432,7 +523,7 @@ namespace Test out << YAML::EndMap; out << YAML::EndSeq; - desiredOutput = "-\n key 1: value 1\n key 2: [a, b, c]\n-\n ? [1, 2]\n :\n a: b"; + desiredOutput = "---\n-\n key 1: value 1\n key 2: [a, b, c]\n-\n ? [1, 2]\n :\n a: b"; } void Null(YAML::Emitter& out, std::string& desiredOutput) @@ -445,26 +536,26 @@ namespace Test out << YAML::EndMap; out << YAML::EndSeq; - desiredOutput = "- ~\n-\n null value: ~\n ~: null key"; + desiredOutput = "---\n- ~\n-\n null value: ~\n ~: null key"; } void EscapedUnicode(YAML::Emitter& out, std::string& desiredOutput) { out << YAML::EscapeNonAscii << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; - desiredOutput = "\"$ \\xa2 \\u20ac \\U00024b62\""; + desiredOutput = "--- \"$ \\xa2 \\u20ac \\U00024b62\""; } void Unicode(YAML::Emitter& out, std::string& desiredOutput) { out << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; - desiredOutput = "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; + desiredOutput = "--- \x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; } void DoubleQuotedUnicode(YAML::Emitter& out, std::string& desiredOutput) { out << YAML::DoubleQuoted << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; - desiredOutput = "\"\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2\""; + desiredOutput = "--- \"\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2\""; } @@ -620,6 +711,16 @@ namespace Test RunEmitterTest(&Emitter::BlockMapAsKey, "block map as key", passed, total); RunEmitterTest(&Emitter::AliasAndAnchor, "alias and anchor", passed, total); RunEmitterTest(&Emitter::AliasAndAnchorWithNull, "alias and anchor with null", passed, total); + RunEmitterTest(&Emitter::SimpleVerbatimTag, "simple verbatim tag", passed, total); + RunEmitterTest(&Emitter::VerbatimTagInBlockSeq, "verbatim tag in block seq", passed, total); + RunEmitterTest(&Emitter::VerbatimTagInFlowSeq, "verbatim tag in flow seq", passed, total); + RunEmitterTest(&Emitter::VerbatimTagInFlowSeqWithNull, "verbatim tag in flow seq with null", passed, total); + RunEmitterTest(&Emitter::VerbatimTagInBlockMap, "verbatim tag in block map", passed, total); + RunEmitterTest(&Emitter::VerbatimTagInFlowMap, "verbatim tag in flow map", passed, total); + RunEmitterTest(&Emitter::VerbatimTagInFlowMapWithNull, "verbatim tag in flow map with null", passed, total); + RunEmitterTest(&Emitter::VerbatimTagWithEmptySeq, "verbatim tag with empty seq", passed, total); + RunEmitterTest(&Emitter::VerbatimTagWithEmptyMap, "verbatim tag with empty map", passed, total); + RunEmitterTest(&Emitter::VerbatimTagWithEmptySeqAndMap, "verbatim tag with empty seq and map", passed, total); RunEmitterTest(&Emitter::ComplexDoc, "complex doc", passed, total); RunEmitterTest(&Emitter::STLContainers, "STL containers", passed, total); RunEmitterTest(&Emitter::SimpleComment, "simple comment", passed, total); diff --git a/test/spectests.cpp b/test/spectests.cpp index c4da43f..0043c3a 100644 --- a/test/spectests.cpp +++ b/test/spectests.cpp @@ -32,7 +32,7 @@ namespace Test { ret = test(); } catch(const YAML::Exception& e) { ret.ok = false; - ret.error = " Exception caught: " + e.msg; + ret.error = std::string(" Exception caught: ") + e.what(); } if(!ret.ok) { @@ -459,7 +459,136 @@ namespace Test { return true; } - // TODO: 2.19 - 2.26 tags + // TODO: 2.19 - 2.22 tags + + // 2.23 + TEST VariousExplicitTags() + { + std::string input = + "---\n" + "not-date: !!str 2002-04-28\n" + "\n" + "picture: !!binary |\n" + " R0lGODlhDAAMAIQAAP//9/X\n" + " 17unp5WZmZgAAAOfn515eXv\n" + " Pz7Y6OjuDg4J+fn5OTk6enp\n" + " 56enmleECcgggoBADs=\n" + "\n" + "application specific tag: !something |\n" + " The semantics of the tag\n" + " above may be different for\n" + " different documents."; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["not-date"].GetTag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(doc["not-date"] == "2002-04-28"); + YAML_ASSERT(doc["picture"].GetTag() == "tag:yaml.org,2002:binary"); + YAML_ASSERT(doc["picture"] == + "R0lGODlhDAAMAIQAAP//9/X\n" + "17unp5WZmZgAAAOfn515eXv\n" + "Pz7Y6OjuDg4J+fn5OTk6enp\n" + "56enmleECcgggoBADs=\n" + ); + YAML_ASSERT(doc["application specific tag"].GetTag() == "!something"); + YAML_ASSERT(doc["application specific tag"] == + "The semantics of the tag\n" + "above may be different for\n" + "different documents." + ); + return true; + } + + // 2.24 + TEST GlobalTags() + { + std::string input = + "%TAG ! tag:clarkevans.com,2002:\n" + "--- !shape\n" + " # Use the ! handle for presenting\n" + " # tag:clarkevans.com,2002:circle\n" + "- !circle\n" + " center: &ORIGIN {x: 73, y: 129}\n" + " radius: 7\n" + "- !line\n" + " start: *ORIGIN\n" + " finish: { x: 89, y: 102 }\n" + "- !label\n" + " start: *ORIGIN\n" + " color: 0xFFEEBB\n" + " text: Pretty vector drawing."; + + PARSE(doc, input); + YAML_ASSERT(doc.GetTag() == "tag:clarkevans.com,2002:shape"); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc[0].GetTag() == "tag:clarkevans.com,2002:circle"); + YAML_ASSERT(doc[0].size() == 2); + YAML_ASSERT(doc[0]["center"].size() == 2); + YAML_ASSERT(doc[0]["center"]["x"] == 73); + YAML_ASSERT(doc[0]["center"]["y"] == 129); + YAML_ASSERT(doc[0]["radius"] == 7); + YAML_ASSERT(doc[1].GetTag() == "tag:clarkevans.com,2002:line"); + YAML_ASSERT(doc[1].size() == 2); + YAML_ASSERT(doc[1]["start"].size() == 2); + YAML_ASSERT(doc[1]["start"]["x"] == 73); + YAML_ASSERT(doc[1]["start"]["y"] == 129); + YAML_ASSERT(doc[1]["finish"].size() == 2); + YAML_ASSERT(doc[1]["finish"]["x"] == 89); + YAML_ASSERT(doc[1]["finish"]["y"] == 102); + YAML_ASSERT(doc[2].GetTag() == "tag:clarkevans.com,2002:label"); + YAML_ASSERT(doc[2].size() == 3); + YAML_ASSERT(doc[2]["start"].size() == 2); + YAML_ASSERT(doc[2]["start"]["x"] == 73); + YAML_ASSERT(doc[2]["start"]["y"] == 129); + YAML_ASSERT(doc[2]["color"] == "0xFFEEBB"); + YAML_ASSERT(doc[2]["text"] == "Pretty vector drawing."); + return true; + } + + // 2.25 + TEST UnorderedSets() + { + std::string input = + "# Sets are represented as a\n" + "# Mapping where each key is\n" + "# associated with a null value\n" + "--- !!set\n" + "? Mark McGwire\n" + "? Sammy Sosa\n" + "? Ken Griffey"; + + PARSE(doc, input); + YAML_ASSERT(doc.GetTag() == "tag:yaml.org,2002:set"); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(IsNull(doc["Mark McGwire"])); + YAML_ASSERT(IsNull(doc["Sammy Sosa"])); + YAML_ASSERT(IsNull(doc["Ken Griffey"])); + return true; + } + + // 2.26 + TEST OrderedMappings() + { + std::string input = + "# Ordered maps are represented as\n" + "# A sequence of mappings, with\n" + "# each mapping having one key\n" + "--- !!omap\n" + "- Mark McGwire: 65\n" + "- Sammy Sosa: 63\n" + "- Ken Griffey: 58"; + + PARSE(doc, input); + YAML_ASSERT(doc.GetTag() == "tag:yaml.org,2002:omap"); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc[0].size() == 1); + YAML_ASSERT(doc[0]["Mark McGwire"] == 65); + YAML_ASSERT(doc[1].size() == 1); + YAML_ASSERT(doc[1]["Sammy Sosa"] == 63); + YAML_ASSERT(doc[2].size() == 1); + YAML_ASSERT(doc[2]["Ken Griffey"] == 58); + return true; + } // 2.27 TEST Invoice() @@ -496,6 +625,7 @@ namespace Test { " Billsmer @ 338-4338."; PARSE(doc, input); + YAML_ASSERT(doc.GetTag() == "tag:clarkevans.com,2002:invoice"); YAML_ASSERT(doc.size() == 8); YAML_ASSERT(doc["invoice"] == 34843); YAML_ASSERT(doc["date"] == "2001-01-23"); @@ -993,8 +1123,291 @@ namespace Test { return true; } - // TODO: 6.13 - 6.17 directives - // TODO: 6.18 - 6.28 tags + // 6.13 + TEST ReservedDirectives() + { + std::string input = + "%FOO bar baz # Should be ignored\n" + " # with a warning.\n" + "--- \"foo\""; + + PARSE(doc, input); + return true; + } + + // 6.14 + TEST YAMLDirective() + { + std::string input = + "%YAML 1.3 # Attempt parsing\n" + " # with a warning\n" + "---\n" + "\"foo\""; + + PARSE(doc, input); + return true; + } + + // 6.15 + TEST InvalidRepeatedYAMLDirective() + { + std::string input = + "%YAML 1.2\n" + "%YAML 1.1\n" + "foo"; + + try { + PARSE(doc, input); + } catch(const YAML::ParserException& e) { + if(e.msg == YAML::ErrorMsg::REPEATED_YAML_DIRECTIVE) + return true; + + throw; + } + + return " No exception was thrown"; + } + + // 6.16 + TEST TagDirective() + { + std::string input = + "%TAG !yaml! tag:yaml.org,2002:\n" + "---\n" + "!yaml!str \"foo\""; + + PARSE(doc, input); + YAML_ASSERT(doc.GetTag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(doc == "foo"); + return true; + } + + // 6.17 + TEST InvalidRepeatedTagDirective() + { + std::string input = + "%TAG ! !foo\n" + "%TAG ! !foo\n" + "bar"; + + try { + PARSE(doc, input); + } catch(const YAML::ParserException& e) { + if(e.msg == YAML::ErrorMsg::REPEATED_TAG_DIRECTIVE) + return true; + + throw; + } + + return " No exception was thrown"; + } + + // 6.18 + TEST PrimaryTagHandle() + { + std::string input = + "# Private\n" + "!foo \"bar\"\n" + "...\n" + "# Global\n" + "%TAG ! tag:example.com,2000:app/\n" + "---\n" + "!foo \"bar\""; + + PARSE(doc, input); + YAML_ASSERT(doc.GetTag() == "!foo"); + YAML_ASSERT(doc == "bar"); + + PARSE_NEXT(doc); + YAML_ASSERT(doc.GetTag() == "tag:example.com,2000:app/foo"); + YAML_ASSERT(doc == "bar"); + return true; + } + + // 6.19 + TEST SecondaryTagHandle() + { + std::string input = + "%TAG !! tag:example.com,2000:app/\n" + "---\n" + "!!int 1 - 3 # Interval, not integer"; + + PARSE(doc, input); + YAML_ASSERT(doc.GetTag() == "tag:example.com,2000:app/int"); + YAML_ASSERT(doc == "1 - 3"); + return true; + } + + // 6.20 + TEST TagHandles() + { + std::string input = + "%TAG !e! tag:example.com,2000:app/\n" + "---\n" + "!e!foo \"bar\""; + + PARSE(doc, input); + YAML_ASSERT(doc.GetTag() == "tag:example.com,2000:app/foo"); + YAML_ASSERT(doc == "bar"); + return true; + } + + // 6.21 + TEST LocalTagPrefix() + { + std::string input = + "%TAG !m! !my-\n" + "--- # Bulb here\n" + "!m!light fluorescent\n" + "...\n" + "%TAG !m! !my-\n" + "--- # Color here\n" + "!m!light green"; + + PARSE(doc, input); + YAML_ASSERT(doc.GetTag() == "!my-light"); + YAML_ASSERT(doc == "fluorescent"); + + PARSE_NEXT(doc); + YAML_ASSERT(doc.GetTag() == "!my-light"); + YAML_ASSERT(doc == "green"); + return true; + } + + // 6.22 + TEST GlobalTagPrefix() + { + std::string input = + "%TAG !e! tag:example.com,2000:app/\n" + "---\n" + "- !e!foo \"bar\""; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc[0].GetTag() == "tag:example.com,2000:app/foo"); + YAML_ASSERT(doc[0] == "bar"); + return true; + } + + // 6.23 + TEST NodeProperties() + { + std::string input = + "!!str &a1 \"foo\":\n" + " !!str bar\n" + "&a2 baz : *a1"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + for(YAML::Iterator it=doc.begin();it!=doc.end();++it) { + if(it.first() == "foo") { + YAML_ASSERT(it.first().GetTag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(it.second().GetTag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(it.second() == "bar"); + } else if(it.first() == "baz") { + YAML_ASSERT(it.second() == "foo"); + } else + return " unknown key"; + } + + return true; + } + + // 6.24 + TEST VerbatimTags() + { + std::string input = + "! foo :\n" + " ! baz"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 1); + for(YAML::Iterator it=doc.begin();it!=doc.end();++it) { + YAML_ASSERT(it.first().GetTag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(it.first() == "foo"); + YAML_ASSERT(it.second().GetTag() == "!bar"); + YAML_ASSERT(it.second() == "baz"); + } + return true; + } + + // 6.25 + TEST InvalidVerbatimTags() + { + std::string input = + "- ! foo\n" + "- !<$:?> bar\n"; + + PARSE(doc, input); + return " not implemented yet"; // TODO: check tags (but we probably will say these are valid, I think) + } + + // 6.26 + TEST TagShorthands() + { + std::string input = + "%TAG !e! tag:example.com,2000:app/\n" + "---\n" + "- !local foo\n" + "- !!str bar\n" + "- !e!tag%21 baz\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc[0].GetTag() == "!local"); + YAML_ASSERT(doc[0] == "foo"); + YAML_ASSERT(doc[1].GetTag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(doc[1] == "bar"); + YAML_ASSERT(doc[2].GetTag() == "tag:example.com,2000:app/tag%21"); + YAML_ASSERT(doc[2] == "baz"); + return true; + } + + // 6.27 + TEST InvalidTagShorthands() + { + std::string input1 = + "%TAG !e! tag:example,2000:app/\n" + "---\n" + "- !e! foo"; + + bool threw = false; + try { + PARSE(doc, input1); + } catch(const YAML::ParserException& e) { + threw = true; + if(e.msg != YAML::ErrorMsg::TAG_WITH_NO_SUFFIX) + throw; + } + + if(!threw) + return " No exception was thrown for a tag with no suffix"; + + std::string input2 = + "%TAG !e! tag:example,2000:app/\n" + "---\n" + "- !h!bar baz"; + + PARSE(doc, input2); // TODO: should we reject this one (since !h! is not declared)? + return " not implemented yet"; + } + + // 6.28 + TEST NonSpecificTags() + { + std::string input = + "# Assuming conventional resolution:\n" + "- \"12\"\n" + "- 12\n" + "- ! 12"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc[0] == "12"); // TODO: check tags. How? + YAML_ASSERT(doc[1] == 12); + YAML_ASSERT(doc[2] == "12"); + return true; + } // 6.29 TEST NodeAnchors() @@ -1039,8 +1452,16 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["foo"] == ""); // TODO: check tag - YAML_ASSERT(doc[""] == "bar"); + for(YAML::Iterator it=doc.begin();it!=doc.end();++it) { + if(it.first() == "foo") { + YAML_ASSERT(it.second().GetTag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(it.second() == ""); + } else if(it.first() == "") { + YAML_ASSERT(it.first().GetTag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(it.second() == "bar"); + } else + return " unexpected key"; + } return true; } @@ -1232,6 +1653,10 @@ namespace Test { RunSpecTest(&Spec::QuotedScalars, "2.17", "Quoted scalars", passed, total); RunSpecTest(&Spec::MultiLineFlowScalars, "2.18", "Multi-line flow scalars", passed, total); + RunSpecTest(&Spec::VariousExplicitTags, "2.23", "Various Explicit Tags", passed, total); + RunSpecTest(&Spec::GlobalTags, "2.24", "Global Tags", passed, total); + RunSpecTest(&Spec::UnorderedSets, "2.25", "Unordered Sets", passed, total); + RunSpecTest(&Spec::OrderedMappings, "2.26", "Ordered Mappings", passed, total); RunSpecTest(&Spec::Invoice, "2.27", "Invoice", passed, total); RunSpecTest(&Spec::LogFile, "2.28", "Log File", passed, total); @@ -1255,8 +1680,24 @@ namespace Test { RunSpecTest(&Spec::FlowFolding, "6.8", "Flow Folding", passed, total); RunSpecTest(&Spec::SeparatedComment, "6.9", "Separated Comment", passed, total); RunSpecTest(&Spec::CommentLines, "6.10", "Comment Lines", passed, total); - RunSpecTest(&Spec::SeparationSpacesII, "6.11", "Separation Spaces", passed, total); - + RunSpecTest(&Spec::MultiLineComments, "6.11", "Multi-Line Comments", passed, total); + RunSpecTest(&Spec::SeparationSpacesII, "6.12", "Separation Spaces", passed, total); + RunSpecTest(&Spec::ReservedDirectives, "6.13", "Reserved Directives", passed, total); + RunSpecTest(&Spec::YAMLDirective, "6.14", "YAML Directive", passed, total); + RunSpecTest(&Spec::InvalidRepeatedYAMLDirective, "6.15", "Invalid Repeated YAML Directive", passed, total); + RunSpecTest(&Spec::TagDirective, "6.16", "Tag Directive", passed, total); + RunSpecTest(&Spec::InvalidRepeatedTagDirective, "6.17", "Invalid Repeated Tag Directive", passed, total); + RunSpecTest(&Spec::PrimaryTagHandle, "6.18", "Primary Tag Handle", passed, total); + RunSpecTest(&Spec::SecondaryTagHandle, "6.19", "SecondaryTagHandle", passed, total); + RunSpecTest(&Spec::TagHandles, "6.20", "TagHandles", passed, total); + RunSpecTest(&Spec::LocalTagPrefix, "6.21", "LocalTagPrefix", passed, total); + RunSpecTest(&Spec::GlobalTagPrefix, "6.22", "GlobalTagPrefix", passed, total); + RunSpecTest(&Spec::NodeProperties, "6.23", "NodeProperties", passed, total); + RunSpecTest(&Spec::VerbatimTags, "6.24", "Verbatim Tags", passed, total); + RunSpecTest(&Spec::InvalidVerbatimTags, "6.25", "Invalid Verbatim Tags", passed, total); + RunSpecTest(&Spec::TagShorthands, "6.26", "Tag Shorthands", passed, total); + RunSpecTest(&Spec::InvalidTagShorthands, "6.27", "Invalid Tag Shorthands", passed, total); + RunSpecTest(&Spec::NonSpecificTags, "6.28", "Non Specific Tags", passed, total); RunSpecTest(&Spec::NodeAnchors, "6.29", "Node Anchors", passed, total); RunSpecTest(&Spec::AliasNodes, "7.1", "Alias Nodes", passed, total); From 72413bafd4e2688c1e4191e8a3a24982e346c524 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 29 Oct 2009 19:41:46 +0000 Subject: [PATCH 197/295] Added ability to read compact maps in a flow sequence --- src/map.cpp | 30 ++++++++++++++++++++++++++++++ src/map.h | 1 + src/node.cpp | 1 + src/scanner.cpp | 24 +++++++++++++++++------- src/scanner.h | 2 ++ src/scantoken.cpp | 18 +++++++++++++----- src/simplekey.cpp | 16 +++++++++------- src/token.h | 2 ++ 8 files changed, 75 insertions(+), 19 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 4607966..7159d42 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -65,6 +65,7 @@ namespace YAML switch(pScanner->peek().type) { case Token::BLOCK_MAP_START: ParseBlock(pScanner, state); break; case Token::FLOW_MAP_START: ParseFlow(pScanner, state); break; + case Token::FLOW_MAP_COMPACT: ParseCompact(pScanner, state); break; default: break; } } @@ -148,6 +149,35 @@ namespace YAML } } + // ParseCompact + // . Single key: value pair in a flow sequence + void Map::ParseCompact(Scanner *pScanner, const ParserState& state) + { + // eat start token + pScanner->pop(); + + if(pScanner->empty()) + throw ParserException(Mark::null(), ErrorMsg::END_OF_MAP_FLOW); + + Token& token = pScanner->peek(); + std::auto_ptr 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); + } + + // assign the map with the actual pointers + m_data[pKey.release()] = pValue.release(); + } + void Map::Write(Emitter& out) const { out << BeginMap; diff --git a/src/map.h b/src/map.h index 8cb67cb..c92b05f 100644 --- a/src/map.h +++ b/src/map.h @@ -41,6 +41,7 @@ namespace YAML private: void ParseBlock(Scanner *pScanner, const ParserState& state); void ParseFlow(Scanner *pScanner, const ParserState& state); + void ParseCompact(Scanner *pScanner, const ParserState& state); private: node_map m_data; diff --git a/src/node.cpp b/src/node.cpp index 178377f..f2fa118 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -97,6 +97,7 @@ namespace YAML break; case Token::FLOW_MAP_START: case Token::BLOCK_MAP_START: + case Token::FLOW_MAP_COMPACT: m_pContent = new Map; break; default: diff --git a/src/scanner.cpp b/src/scanner.cpp index 877c404..81900d0 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -253,6 +253,22 @@ namespace YAML m_endedStream = true; } + Token *Scanner::PushToken(Token::TYPE type) + { + m_tokens.push(Token(type, INPUT.mark())); + return &m_tokens.back(); + } + + Token::TYPE Scanner::GetStartTokenFor(IndentMarker::INDENT_TYPE type) const + { + switch(type) { + case IndentMarker::SEQ: return Token::BLOCK_SEQ_START; + case IndentMarker::MAP: return Token::BLOCK_MAP_START; + case IndentMarker::NONE: assert(false); break; + } + assert(false); + } + // PushIndentTo // . Pushes an indentation onto the stack, and enqueues the // proper token (sequence start or mapping start). @@ -274,13 +290,7 @@ namespace YAML return 0; // push a start token - if(type == IndentMarker::SEQ) - m_tokens.push(Token(Token::BLOCK_SEQ_START, INPUT.mark())); - else if(type == IndentMarker::MAP) - m_tokens.push(Token(Token::BLOCK_MAP_START, INPUT.mark())); - else - assert(false); - indent.pStartToken = &m_tokens.back(); + indent.pStartToken = PushToken(GetStartTokenFor(type)); // and then the indent m_indents.push(&indent); diff --git a/src/scanner.h b/src/scanner.h index ddae0de..a0ac7ee 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -54,11 +54,13 @@ namespace YAML void ScanToNextToken(); void StartStream(); void EndStream(); + Token *PushToken(Token::TYPE type); bool InFlowContext() const { return !m_flows.empty(); } bool InBlockContext() const { return m_flows.empty(); } int GetFlowLevel() const { return m_flows.size(); } + Token::TYPE GetStartTokenFor(IndentMarker::INDENT_TYPE type) const; IndentMarker *PushIndentTo(int column, IndentMarker::INDENT_TYPE type); void PopIndentToHere(); void PopAllIndents(); diff --git a/src/scantoken.cpp b/src/scantoken.cpp index c1551ac..b026356 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -103,8 +103,12 @@ namespace YAML throw ParserException(INPUT.mark(), ErrorMsg::FLOW_END); // we might have a solo entry in the flow context - if(VerifySimpleKey()) - m_tokens.push(Token(Token::VALUE, INPUT.mark())); + if(InFlowContext()) { + if(m_flows.top() == FLOW_MAP && VerifySimpleKey()) + m_tokens.push(Token(Token::VALUE, INPUT.mark())); + else if(m_flows.top() == FLOW_SEQ) + InvalidateSimpleKey(); + } m_simpleKeyAllowed = false; @@ -125,9 +129,13 @@ namespace YAML // FlowEntry void Scanner::ScanFlowEntry() { - // we might have a solo entry in the flow context - if(VerifySimpleKey()) - m_tokens.push(Token(Token::VALUE, INPUT.mark())); + // we might have a solo entry in the flow context + if(InFlowContext()) { + if(m_flows.top() == FLOW_MAP && VerifySimpleKey()) + m_tokens.push(Token(Token::VALUE, INPUT.mark())); + else if(m_flows.top() == FLOW_SEQ) + InvalidateSimpleKey(); + } m_simpleKeyAllowed = true; diff --git a/src/simplekey.cpp b/src/simplekey.cpp index f99cea6..fe308ed 100644 --- a/src/simplekey.cpp +++ b/src/simplekey.cpp @@ -38,9 +38,6 @@ namespace YAML { if(!m_simpleKeyAllowed) return false; - - if(InFlowContext() && m_flows.top() != FLOW_MAP) - return false; return !ExistsActiveSimpleKey(); } @@ -68,10 +65,15 @@ namespace YAML SimpleKey key(INPUT.mark(), GetFlowLevel()); // first add a map start, if necessary - key.pIndent = PushIndentTo(INPUT.column(), IndentMarker::MAP); - if(key.pIndent) { - key.pIndent->status = IndentMarker::UNKNOWN; - key.pMapStart = key.pIndent->pStartToken; + if(InBlockContext()) { + key.pIndent = PushIndentTo(INPUT.column(), IndentMarker::MAP); + if(key.pIndent) { + key.pIndent->status = IndentMarker::UNKNOWN; + key.pMapStart = key.pIndent->pStartToken; + key.pMapStart->status = Token::UNVERIFIED; + } + } else if(m_flows.top() == FLOW_SEQ) { + key.pMapStart = PushToken(Token::FLOW_MAP_COMPACT); key.pMapStart->status = Token::UNVERIFIED; } diff --git a/src/token.h b/src/token.h index ff1a457..cf7c0fe 100644 --- a/src/token.h +++ b/src/token.h @@ -24,6 +24,7 @@ namespace YAML "FLOW_MAP_START", "FLOW_SEQ_END", "FLOW_MAP_END", + "FLOW_MAP_COMPACT", "FLOW_ENTRY", "KEY", "VALUE", @@ -49,6 +50,7 @@ namespace YAML FLOW_MAP_START, FLOW_SEQ_END, FLOW_MAP_END, + FLOW_MAP_COMPACT, FLOW_ENTRY, KEY, VALUE, From 5618157a1e1a18abcb091b4693e851697db01622 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 29 Oct 2009 20:35:07 +0000 Subject: [PATCH 198/295] Added flow collection tests --- test/spectests.cpp | 200 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) diff --git a/test/spectests.cpp b/test/spectests.cpp index 0043c3a..fb5150d 100644 --- a/test/spectests.cpp +++ b/test/spectests.cpp @@ -1628,6 +1628,196 @@ namespace Test { YAML_ASSERT(doc == "1st non-empty\n2nd non-empty 3rd non-empty"); return true; } + + // 7.13 + TEST FlowSequence() + { + std::string input = + "- [ one, two, ]\n" + "- [three ,four]"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc[0].size() == 2); + YAML_ASSERT(doc[0][0] == "one"); + YAML_ASSERT(doc[0][1] == "two"); + YAML_ASSERT(doc[1].size() == 2); + YAML_ASSERT(doc[1][0] == "three"); + YAML_ASSERT(doc[1][1] == "four"); + return true; + } + + // 7.14 + TEST FlowSequenceEntries() + { + std::string input = + "[\n" + "\"double\n" + " quoted\", 'single\n" + " quoted',\n" + "plain\n" + " text, [ nested ],\n" + "single: pair,\n" + "]"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 5); + YAML_ASSERT(doc[0] == "double quoted"); + YAML_ASSERT(doc[1] == "single quoted"); + YAML_ASSERT(doc[2] == "plain text"); + YAML_ASSERT(doc[3].size() == 1); + YAML_ASSERT(doc[3][0] == "nested"); + YAML_ASSERT(doc[4].size() == 1); + YAML_ASSERT(doc[4]["single"] == "pair"); + return true; + } + + // 7.15 + TEST FlowMappings() + { + std::string input = + "- { one : two , three: four , }\n" + "- {five: six,seven : eight}"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc[0].size() == 2); + YAML_ASSERT(doc[0]["one"] == "two"); + YAML_ASSERT(doc[0]["three"] == "four"); + YAML_ASSERT(doc[1].size() == 2); + YAML_ASSERT(doc[1]["five"] == "six"); + YAML_ASSERT(doc[1]["seven"] == "eight"); + return true; + } + + // 7.16 + TEST FlowMappingEntries() + { + std::string input = + "{\n" + "? explicit: entry,\n" + "implicit: entry,\n" + "?\n" + "}"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["explicit"] == "entry"); + YAML_ASSERT(doc["implicit"] == "entry"); + YAML_ASSERT(IsNull(doc[YAML::Null])); + return true; + } + + // 7.17 + TEST FlowMappingSeparateValues() + { + std::string input = + "{\n" + "unquoted : \"separate\",\n" + "http://foo.com,\n" + "omitted value:,\n" + ": omitted key,\n" + "}"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 4); + YAML_ASSERT(doc["unquoted"] == "separate"); + YAML_ASSERT(IsNull(doc["http://foo.com"])); + YAML_ASSERT(IsNull(doc["omitted value"])); + YAML_ASSERT(doc[YAML::Null] == "omitted key"); + return true; + } + + // 7.18 + TEST FlowMappingAdjacentValues() + { + std::string input = + "{\n" + "\"adjacent\":value,\n" + "\"readable\":value,\n" + "\"empty\":\n" + "}"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["adjacent"] == "value"); + YAML_ASSERT(doc["readable"] == "value"); + YAML_ASSERT(IsNull(doc["empty"])); + return true; + } + + // 7.19 + TEST SinglePairFlowMappings() + { + std::string input = + "[\n" + "foo: bar\n" + "]"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc[0].size() == 1); + YAML_ASSERT(doc[0]["foo"] == "bar"); + return true; + } + + // 7.20 + TEST SinglePairExplicitEntry() + { + std::string input = + "[\n" + "? foo\n" + " bar : baz\n" + "]"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc[0].size() == 1); + YAML_ASSERT(doc[0]["foo"] == "bar"); + return true; + } + + // 7.21 + TEST SinglePairImplicitEntries() + { + std::string input = + "- [ YAML : separate ]\n" + "- [ : empty key entry ]\n" + "- [ {JSON: like}:adjacent ]"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc[0].size() == 1); + YAML_ASSERT(doc[0][0].size() == 1); + YAML_ASSERT(doc[0][0]["YAML"] == "separate"); + YAML_ASSERT(doc[1].size() == 1); + YAML_ASSERT(doc[1][0].size() == 1); + YAML_ASSERT(doc[1][0][YAML::Null] == "empty key entry"); + YAML_ASSERT(doc[2].size() == 1); + YAML_ASSERT(doc[2][0].size() == 1); + StringMap key; + key._["JSON"] = "like"; + YAML_ASSERT(doc[2][0][key] == "adjacent"); + return true; + } + + // 7.22 + TEST InvalidImplicitKeys() + { + std::string input = + "[ foo\n" + " bar: invalid,"; // Note: we don't check (on purpose) the >1K chars for an implicit key + + try { + PARSE(doc, input); + } catch(const YAML::Exception& e) { + if(e.msg == YAML::ErrorMsg::END_OF_SEQ); + return true; + + throw; + } + return " no exception thrown"; + } } bool RunSpecTests() @@ -1712,6 +1902,16 @@ namespace Test { RunSpecTest(&Spec::PlainCharacters, "7.10", "Plain Characters", passed, total); RunSpecTest(&Spec::PlainImplicitKeys, "7.11", "Plain Implicit Keys", passed, total); RunSpecTest(&Spec::PlainLines, "7.12", "Plain Lines", passed, total); + RunSpecTest(&Spec::FlowSequence, "7.13", "Flow Sequence", passed, total); + RunSpecTest(&Spec::FlowSequenceEntries, "7.14", "Flow Sequence Entries", passed, total); + RunSpecTest(&Spec::FlowMappings, "7.15", "Flow Mappings", passed, total); + RunSpecTest(&Spec::FlowMappingEntries, "7.16", "Flow Mapping Entries", passed, total); + RunSpecTest(&Spec::FlowMappingSeparateValues, "7.17", "Flow Mapping Separate Values", passed, total); + RunSpecTest(&Spec::FlowMappingAdjacentValues, "7.18", "Flow Mapping Adjacent Values", passed, total); + RunSpecTest(&Spec::SinglePairFlowMappings, "7.19", "Single Pair Flow Mappings", passed, total); + RunSpecTest(&Spec::SinglePairExplicitEntry, "7.20", "Single Pair Explicit Entry", passed, total); + RunSpecTest(&Spec::SinglePairImplicitEntries, "7.21", "Single Pair Implicit Entries", passed, total); + RunSpecTest(&Spec::InvalidImplicitKeys, "7.22", "Invalid Implicit Keys", passed, total); std::cout << "Spec tests: " << passed << "/" << total << " passed\n"; return passed == total; From 72dceba671b7d0c7b3e296cc16973a3ab168b68c Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 29 Oct 2009 20:45:20 +0000 Subject: [PATCH 199/295] Added test --- test/spectests.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/test/spectests.cpp b/test/spectests.cpp index fb5150d..d2a8e64 100644 --- a/test/spectests.cpp +++ b/test/spectests.cpp @@ -459,7 +459,7 @@ namespace Test { return true; } - // TODO: 2.19 - 2.22 tags + // TODO: 2.19 - 2.22 schema tags // 2.23 TEST VariousExplicitTags() @@ -765,7 +765,16 @@ namespace Test { return true; } - // TODO: 5.5 comment only + // 5.5 + TEST CommentIndicator() + { + std::string input = + "# Comment only."; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 0); + return true; + } // 5.6 TEST NodePropertyIndicators() @@ -1060,10 +1069,9 @@ namespace Test { " # Comment\n" " \n" "\n"; - std::stringstream stream(input); - YAML::Parser parser(stream); - YAML_ASSERT(!parser); + PARSE(doc, input); + YAML_ASSERT(doc.size() == 0); return true; } From 011a608b5ac79ee2545b6d484e7df82499f92a0a Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 29 Oct 2009 21:05:48 +0000 Subject: [PATCH 200/295] Implemented adjacent key:value pairs when the key is JSON-like --- src/exp.h | 3 ++- src/scanner.cpp | 15 +++++++++++++-- src/scanner.h | 3 +++ src/scantoken.cpp | 13 +++++++++++++ 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/exp.h b/src/exp.h index c84f12a..f8dbc29 100644 --- a/src/exp.h +++ b/src/exp.h @@ -43,7 +43,8 @@ namespace YAML const RegEx Key = RegEx('?'), KeyInFlow = RegEx('?') + BlankOrBreak; const RegEx Value = RegEx(':') + (BlankOrBreak || RegEx()), - ValueInFlow = RegEx(':') + (BlankOrBreak || RegEx(",}", REGEX_OR)); + ValueInFlow = RegEx(':') + (BlankOrBreak || RegEx(",}", REGEX_OR)), + ValueInJSONFlow = RegEx(':'); const RegEx Comment = RegEx('#'); const RegEx AnchorEnd = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak; const RegEx URI = Word || RegEx("#;/?:@&=+$,_.!~*'()[]", REGEX_OR) || (RegEx('%') + Hex + Hex); diff --git a/src/scanner.cpp b/src/scanner.cpp index 81900d0..13963a4 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -8,7 +8,7 @@ namespace YAML { Scanner::Scanner(std::istream& in) - : INPUT(in), m_startedStream(false), m_endedStream(false), m_simpleKeyAllowed(false) + : INPUT(in), m_startedStream(false), m_endedStream(false), m_simpleKeyAllowed(false), m_canBeJSONFlow(false) { } @@ -142,7 +142,7 @@ namespace YAML if((InBlockContext() ? Exp::Key : Exp::KeyInFlow).Matches(INPUT)) return ScanKey(); - if((InBlockContext() ? Exp::Value : Exp::ValueInFlow).Matches(INPUT)) + if(GetValueRegex().Matches(INPUT)) return ScanValue(); // alias/anchor @@ -226,6 +226,16 @@ namespace YAML return false; } + // GetValueRegex + // . Get the appropriate regex to check if it's a value token + const RegEx& Scanner::GetValueRegex() const + { + if(InBlockContext()) + return Exp::Value; + + return m_canBeJSONFlow ? Exp::ValueInJSONFlow : Exp::ValueInFlow; + } + // StartStream // . Set the initial conditions for starting a stream. void Scanner::StartStream() @@ -410,3 +420,4 @@ namespace YAML m_anchors.clear(); } } + diff --git a/src/scanner.h b/src/scanner.h index a0ac7ee..28ce96d 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -16,6 +16,7 @@ namespace YAML { class Node; + class RegEx; class Scanner { @@ -78,6 +79,7 @@ namespace YAML void ThrowParserException(const std::string& msg) const; bool IsWhitespaceToBeEaten(char ch); + const RegEx& GetValueRegex() const; struct SimpleKey { SimpleKey(const Mark& mark_, int flowLevel_); @@ -120,6 +122,7 @@ namespace YAML // state info bool m_startedStream, m_endedStream; bool m_simpleKeyAllowed; + bool m_canBeJSONFlow; std::stack m_simpleKeys; std::stack m_indents; std::vector m_indentRefs; // for "garbage collection" diff --git a/src/scantoken.cpp b/src/scantoken.cpp index b026356..4320364 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -24,6 +24,7 @@ namespace YAML PopAllSimpleKeys(); m_simpleKeyAllowed = false; + m_canBeJSONFlow = false; // store pos and eat indicator Token token(Token::DIRECTIVE, INPUT.mark()); @@ -60,6 +61,7 @@ namespace YAML PopAllIndents(); PopAllSimpleKeys(); m_simpleKeyAllowed = false; + m_canBeJSONFlow = false; // eat Mark mark = INPUT.mark(); @@ -73,6 +75,7 @@ namespace YAML PopAllIndents(); PopAllSimpleKeys(); m_simpleKeyAllowed = false; + m_canBeJSONFlow = false; // eat Mark mark = INPUT.mark(); @@ -86,6 +89,7 @@ namespace YAML // flows can be simple keys InsertPotentialSimpleKey(); m_simpleKeyAllowed = true; + m_canBeJSONFlow = false; // eat Mark mark = INPUT.mark(); @@ -111,6 +115,7 @@ namespace YAML } m_simpleKeyAllowed = false; + m_canBeJSONFlow = true; // eat Mark mark = INPUT.mark(); @@ -138,6 +143,7 @@ namespace YAML } m_simpleKeyAllowed = true; + m_canBeJSONFlow = false; // eat Mark mark = INPUT.mark(); @@ -158,6 +164,7 @@ namespace YAML PushIndentTo(INPUT.column(), IndentMarker::SEQ); m_simpleKeyAllowed = true; + m_canBeJSONFlow = false; // eat Mark mark = INPUT.mark(); @@ -190,6 +197,7 @@ namespace YAML { // and check that simple key bool isSimpleKey = VerifySimpleKey(); + m_canBeJSONFlow = false; if(isSimpleKey) { // can't follow a simple key with another simple key (dunno why, though - it seems fine) @@ -222,6 +230,7 @@ namespace YAML // insert a potential simple key InsertPotentialSimpleKey(); m_simpleKeyAllowed = false; + m_canBeJSONFlow = false; // eat the indicator Mark mark = INPUT.mark(); @@ -252,6 +261,7 @@ namespace YAML // insert a potential simple key InsertPotentialSimpleKey(); m_simpleKeyAllowed = false; + m_canBeJSONFlow = false; Token token(Token::TAG, INPUT.mark()); @@ -305,6 +315,7 @@ namespace YAML // can have a simple key only if we ended the scalar by starting a new line m_simpleKeyAllowed = params.leadingSpaces; + m_canBeJSONFlow = false; // finally, check and see if we ended on an illegal character //if(Exp::IllegalCharInScalar.Matches(INPUT)) @@ -347,6 +358,7 @@ namespace YAML // and scan scalar = ScanScalar(INPUT, params); m_simpleKeyAllowed = false; + m_canBeJSONFlow = true; Token token(Token::SCALAR, mark); token.value = scalar; @@ -413,6 +425,7 @@ namespace YAML // simple keys always ok after block scalars (since we're gonna start a new line anyways) m_simpleKeyAllowed = true; + m_canBeJSONFlow = false; Token token(Token::SCALAR, mark); token.value = scalar; From 7c4a8dad85a13f6fcb62daa22bd23d9266d448e6 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 29 Oct 2009 22:01:01 +0000 Subject: [PATCH 201/295] Added case for parsing a compact key: value pair in a flow sequence with a null key --- src/map.cpp | 15 +++++++++++++++ src/map.h | 1 + src/node.cpp | 7 +++++++ 3 files changed, 23 insertions(+) diff --git a/src/map.cpp b/src/map.cpp index 7159d42..b30d3f7 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -66,6 +66,7 @@ namespace YAML case Token::BLOCK_MAP_START: ParseBlock(pScanner, state); break; case Token::FLOW_MAP_START: ParseFlow(pScanner, state); break; case Token::FLOW_MAP_COMPACT: ParseCompact(pScanner, state); break; + case Token::VALUE: ParseCompactWithNoKey(pScanner, state); break; default: break; } } @@ -178,6 +179,20 @@ namespace YAML m_data[pKey.release()] = pValue.release(); } + // ParseCompactWithNoKey + // . Single key: value pair in a flow sequence + void Map::ParseCompactWithNoKey(Scanner *pScanner, const ParserState& state) + { + std::auto_ptr pKey(new Node), pValue(new Node); + + // grab value + pScanner->pop(); + pValue->Parse(pScanner, state); + + // assign the map with the actual pointers + m_data[pKey.release()] = pValue.release(); + } + void Map::Write(Emitter& out) const { out << BeginMap; diff --git a/src/map.h b/src/map.h index c92b05f..d411010 100644 --- a/src/map.h +++ b/src/map.h @@ -42,6 +42,7 @@ namespace YAML void ParseBlock(Scanner *pScanner, const ParserState& state); void ParseFlow(Scanner *pScanner, const ParserState& state); void ParseCompact(Scanner *pScanner, const ParserState& state); + void ParseCompactWithNoKey(Scanner *pScanner, const ParserState& state); private: node_map m_data; diff --git a/src/node.cpp b/src/node.cpp index f2fa118..0b547a3 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -64,6 +64,13 @@ namespace YAML // 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); From 08ac48518fc3f67365755880de9acf9d483eafb0 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 29 Oct 2009 22:09:50 +0000 Subject: [PATCH 202/295] Refactored the compact map notation, which made it easy to implement explicit keys for compact maps --- src/map.cpp | 21 ++++++--------------- src/node.cpp | 2 +- src/simplekey.cpp | 3 --- test/spectests.cpp | 2 +- 4 files changed, 8 insertions(+), 20 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index b30d3f7..5d33385 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -65,7 +65,7 @@ namespace YAML switch(pScanner->peek().type) { case Token::BLOCK_MAP_START: ParseBlock(pScanner, state); break; case Token::FLOW_MAP_START: ParseFlow(pScanner, state); break; - case Token::FLOW_MAP_COMPACT: ParseCompact(pScanner, state); break; + case Token::KEY: ParseCompact(pScanner, state); break; case Token::VALUE: ParseCompactWithNoKey(pScanner, state); break; default: break; } @@ -151,23 +151,14 @@ namespace YAML } // ParseCompact - // . Single key: value pair in a flow sequence + // . Single "key: value" pair in a flow sequence void Map::ParseCompact(Scanner *pScanner, const ParserState& state) { - // eat start token - pScanner->pop(); - - if(pScanner->empty()) - throw ParserException(Mark::null(), ErrorMsg::END_OF_MAP_FLOW); - - Token& token = pScanner->peek(); std::auto_ptr pKey(new Node), pValue(new Node); - // grab key (if non-null) - if(token.type == Token::KEY) { - pScanner->pop(); - pKey->Parse(pScanner, state); - } + // grab key + pScanner->pop(); + pKey->Parse(pScanner, state); // now grab value (optional) if(!pScanner->empty() && pScanner->peek().type == Token::VALUE) { @@ -180,7 +171,7 @@ namespace YAML } // ParseCompactWithNoKey - // . Single key: value pair in a flow sequence + // . Single ": value" pair in a flow sequence void Map::ParseCompactWithNoKey(Scanner *pScanner, const ParserState& state) { std::auto_ptr pKey(new Node), pValue(new Node); diff --git a/src/node.cpp b/src/node.cpp index 0b547a3..8f66f3b 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -104,7 +104,7 @@ namespace YAML break; case Token::FLOW_MAP_START: case Token::BLOCK_MAP_START: - case Token::FLOW_MAP_COMPACT: + case Token::KEY: m_pContent = new Map; break; default: diff --git a/src/simplekey.cpp b/src/simplekey.cpp index fe308ed..d8d1932 100644 --- a/src/simplekey.cpp +++ b/src/simplekey.cpp @@ -72,9 +72,6 @@ namespace YAML key.pMapStart = key.pIndent->pStartToken; key.pMapStart->status = Token::UNVERIFIED; } - } else if(m_flows.top() == FLOW_SEQ) { - key.pMapStart = PushToken(Token::FLOW_MAP_COMPACT); - key.pMapStart->status = Token::UNVERIFIED; } // then add the (now unverified) key diff --git a/test/spectests.cpp b/test/spectests.cpp index d2a8e64..4bd0e89 100644 --- a/test/spectests.cpp +++ b/test/spectests.cpp @@ -1781,7 +1781,7 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 1); YAML_ASSERT(doc[0].size() == 1); - YAML_ASSERT(doc[0]["foo"] == "bar"); + YAML_ASSERT(doc[0]["foo bar"] == "baz"); return true; } From e8beb6c98f8414be00905f564f23a072d1b536af Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 29 Oct 2009 22:39:53 +0000 Subject: [PATCH 203/295] Fixed mistake in test --- test/spectests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/spectests.cpp b/test/spectests.cpp index 4bd0e89..1857234 100644 --- a/test/spectests.cpp +++ b/test/spectests.cpp @@ -1819,7 +1819,7 @@ namespace Test { try { PARSE(doc, input); } catch(const YAML::Exception& e) { - if(e.msg == YAML::ErrorMsg::END_OF_SEQ); + if(e.msg == YAML::ErrorMsg::END_OF_SEQ_FLOW) return true; throw; From c3f222e4d9022c0fbfd4656b0635a894f619b6b2 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 29 Oct 2009 22:55:50 +0000 Subject: [PATCH 204/295] Fixed the whitespace tracking when we escape a newline in a double-quoted string --- src/scanscalar.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/scanscalar.cpp b/src/scanscalar.cpp index b3a84cb..f7f3519 100644 --- a/src/scanscalar.cpp +++ b/src/scanscalar.cpp @@ -31,6 +31,7 @@ namespace YAML // Phase #1: scan until line ending std::size_t lastNonWhitespaceChar = scalar.size(); + bool escapedNewline = false; while(!params.end.Matches(INPUT) && !Exp::Break.Matches(INPUT)) { if(!INPUT) break; @@ -48,10 +49,11 @@ namespace YAML // escaped newline? (only if we're escaping on slash) if(params.escape == '\\' && Exp::EscBreak.Matches(INPUT)) { - int n = Exp::EscBreak.Match(INPUT); - INPUT.eat(n); + // eat escape character and get out (but preserve trailing whitespace!) + INPUT.get(); lastNonWhitespaceChar = scalar.size(); - continue; + escapedNewline = true; + break; } // escape this? @@ -149,7 +151,7 @@ namespace YAML case FOLD_FLOW: if(nextEmptyLine) scalar += "\n"; - else if(!emptyLine && !nextEmptyLine) + else if(!emptyLine && !nextEmptyLine && !escapedNewline) scalar += " "; break; } From b1f143cfaf080f385ca3c95d0f162bd1149c637a Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 30 Oct 2009 01:06:19 +0000 Subject: [PATCH 205/295] Fixed bug with block maps with null value (the next key was being read as the value) --- include/node.h | 10 +++++----- src/aliascontent.cpp | 2 +- src/aliascontent.h | 2 +- src/content.h | 2 +- src/map.cpp | 20 +++++++++++++++----- src/map.h | 10 +++++----- src/node.cpp | 19 ++++++++++--------- src/parserstate.h | 10 ++++++++++ src/scalar.cpp | 2 +- src/scalar.h | 2 +- src/sequence.cpp | 12 +++++++++--- src/sequence.h | 6 +++--- test/parsertests.cpp | 23 +++++++++++++++++++++++ 13 files changed, 85 insertions(+), 35 deletions(-) diff --git a/include/node.h b/include/node.h index 4218444..097ccd8 100644 --- a/include/node.h +++ b/include/node.h @@ -32,7 +32,7 @@ namespace YAML void Clear(); std::auto_ptr Clone() const; - void Parse(Scanner *pScanner, const ParserState& state); + void Parse(Scanner *pScanner, ParserState& state); CONTENT_TYPE GetType() const; @@ -102,10 +102,10 @@ namespace YAML Node(const Mark& mark, const std::string& anchor, const std::string& tag, const Content *pContent); // helpers for parsing - void ParseHeader(Scanner *pScanner, const ParserState& state); - void ParseTag(Scanner *pScanner, const ParserState& state); - void ParseAnchor(Scanner *pScanner, const ParserState& state); - void ParseAlias(Scanner *pScanner, const ParserState& state); + 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; diff --git a/src/aliascontent.cpp b/src/aliascontent.cpp index 305abdc..111938b 100644 --- a/src/aliascontent.cpp +++ b/src/aliascontent.cpp @@ -12,7 +12,7 @@ namespace YAML return 0; // TODO: how to clone an alias? } - void AliasContent::Parse(Scanner * /*pScanner*/, const ParserState& /*state*/) + void AliasContent::Parse(Scanner * /*pScanner*/, ParserState& /*state*/) { } diff --git a/src/aliascontent.h b/src/aliascontent.h index d4cbb56..a69c28b 100644 --- a/src/aliascontent.h +++ b/src/aliascontent.h @@ -15,7 +15,7 @@ namespace YAML virtual Content *Clone() const; - virtual void Parse(Scanner* pScanner, const ParserState& state); + virtual void Parse(Scanner* pScanner, ParserState& state); virtual void Write(Emitter&) const; virtual bool GetBegin(std::vector ::const_iterator&) const; diff --git a/src/content.h b/src/content.h index 90e265c..d6e0e8c 100644 --- a/src/content.h +++ b/src/content.h @@ -28,7 +28,7 @@ namespace YAML virtual Content *Clone() const = 0; - virtual void Parse(Scanner *pScanner, const ParserState& state) = 0; + virtual void Parse(Scanner *pScanner, ParserState& state) = 0; virtual void Write(Emitter& out) const = 0; virtual bool GetBegin(std::vector ::const_iterator&) const { return false; } diff --git a/src/map.cpp b/src/map.cpp index 5d33385..3a6a299 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -57,7 +57,7 @@ namespace YAML return m_data.size(); } - void Map::Parse(Scanner *pScanner, const ParserState& state) + void Map::Parse(Scanner *pScanner, ParserState& state) { Clear(); @@ -71,10 +71,11 @@ namespace YAML } } - void Map::ParseBlock(Scanner *pScanner, const ParserState& state) + void Map::ParseBlock(Scanner *pScanner, ParserState& state) { // eat start token pScanner->pop(); + state.PushCollectionType(ParserState::BLOCK_MAP); while(1) { if(pScanner->empty()) @@ -106,12 +107,15 @@ namespace YAML // assign the map with the actual pointers m_data[pKey.release()] = pValue.release(); } + + state.PopCollectionType(ParserState::BLOCK_MAP); } - void Map::ParseFlow(Scanner *pScanner, const ParserState& state) + void Map::ParseFlow(Scanner *pScanner, ParserState& state) { // eat start token pScanner->pop(); + state.PushCollectionType(ParserState::FLOW_MAP); while(1) { if(pScanner->empty()) @@ -148,12 +152,15 @@ namespace YAML // assign the map with the actual pointers m_data[pKey.release()] = pValue.release(); } + + state.PopCollectionType(ParserState::FLOW_MAP); } // ParseCompact // . Single "key: value" pair in a flow sequence - void Map::ParseCompact(Scanner *pScanner, const ParserState& state) + void Map::ParseCompact(Scanner *pScanner, ParserState& state) { + state.PushCollectionType(ParserState::COMPACT_MAP); std::auto_ptr pKey(new Node), pValue(new Node); // grab key @@ -168,12 +175,14 @@ namespace YAML // assign the map with the actual pointers m_data[pKey.release()] = pValue.release(); + state.PopCollectionType(ParserState::COMPACT_MAP); } // ParseCompactWithNoKey // . Single ": value" pair in a flow sequence - void Map::ParseCompactWithNoKey(Scanner *pScanner, const ParserState& state) + void Map::ParseCompactWithNoKey(Scanner *pScanner, ParserState& state) { + state.PushCollectionType(ParserState::COMPACT_MAP); std::auto_ptr pKey(new Node), pValue(new Node); // grab value @@ -182,6 +191,7 @@ namespace YAML // assign the map with the actual pointers m_data[pKey.release()] = pValue.release(); + state.PopCollectionType(ParserState::COMPACT_MAP); } void Map::Write(Emitter& out) const diff --git a/src/map.h b/src/map.h index d411010..bb8f949 100644 --- a/src/map.h +++ b/src/map.h @@ -27,7 +27,7 @@ namespace YAML virtual bool GetBegin(std::map ::const_iterator& it) const; virtual bool GetEnd(std::map ::const_iterator& it) const; virtual std::size_t GetSize() const; - virtual void Parse(Scanner *pScanner, const ParserState& state); + virtual void Parse(Scanner *pScanner, ParserState& state); virtual void Write(Emitter& out) const; virtual bool IsMap() const { return true; } @@ -39,10 +39,10 @@ namespace YAML virtual int Compare(Map *pMap); private: - void ParseBlock(Scanner *pScanner, const ParserState& state); - void ParseFlow(Scanner *pScanner, const ParserState& state); - void ParseCompact(Scanner *pScanner, const ParserState& state); - void ParseCompactWithNoKey(Scanner *pScanner, const ParserState& state); + void ParseBlock(Scanner *pScanner, ParserState& state); + void ParseFlow(Scanner *pScanner, ParserState& state); + void ParseCompact(Scanner *pScanner, ParserState& state); + void ParseCompactWithNoKey(Scanner *pScanner, ParserState& state); private: node_map m_data; diff --git a/src/node.cpp b/src/node.cpp index 8f66f3b..198bb71 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -54,7 +54,7 @@ namespace YAML return std::auto_ptr (new Node(m_mark, m_anchor, m_tag, m_pContent)); } - void Node::Parse(Scanner *pScanner, const ParserState& state) + void Node::Parse(Scanner *pScanner, ParserState& state) { Clear(); @@ -104,13 +104,14 @@ namespace YAML break; case Token::FLOW_MAP_START: case Token::BLOCK_MAP_START: - case Token::KEY: 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: -// std::stringstream str; -// str << TokenNames[pScanner->peek().type]; -// throw std::runtime_error(str.str()); break; } @@ -125,7 +126,7 @@ namespace YAML // ParseHeader // . Grabs any tag, alias, or anchor tokens and deals with them. - void Node::ParseHeader(Scanner *pScanner, const ParserState& state) + void Node::ParseHeader(Scanner *pScanner, ParserState& state) { while(1) { if(pScanner->empty()) @@ -140,7 +141,7 @@ namespace YAML } } - void Node::ParseTag(Scanner *pScanner, const ParserState& state) + void Node::ParseTag(Scanner *pScanner, ParserState& state) { Token& token = pScanner->peek(); if(m_tag != "") @@ -151,7 +152,7 @@ namespace YAML pScanner->pop(); } - void Node::ParseAnchor(Scanner *pScanner, const ParserState& /*state*/) + void Node::ParseAnchor(Scanner *pScanner, ParserState& /*state*/) { Token& token = pScanner->peek(); if(m_anchor != "") @@ -162,7 +163,7 @@ namespace YAML pScanner->pop(); } - void Node::ParseAlias(Scanner *pScanner, const ParserState& /*state*/) + void Node::ParseAlias(Scanner *pScanner, ParserState& /*state*/) { Token& token = pScanner->peek(); if(m_anchor != "") diff --git a/src/parserstate.h b/src/parserstate.h index 09b4afd..0b849c3 100644 --- a/src/parserstate.h +++ b/src/parserstate.h @@ -6,6 +6,8 @@ #include #include +#include +#include namespace YAML { @@ -16,11 +18,19 @@ namespace YAML 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 tags; + std::stack collectionStack; }; } diff --git a/src/scalar.cpp b/src/scalar.cpp index dbf45b3..415bace 100644 --- a/src/scalar.cpp +++ b/src/scalar.cpp @@ -24,7 +24,7 @@ namespace YAML return new Scalar(m_data); } - void Scalar::Parse(Scanner *pScanner, const ParserState& /*state*/) + void Scalar::Parse(Scanner *pScanner, ParserState& /*state*/) { Token& token = pScanner->peek(); m_data = token.value; diff --git a/src/scalar.h b/src/scalar.h index fe9a84b..1baecaa 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -18,7 +18,7 @@ namespace YAML virtual Content *Clone() const; - virtual void Parse(Scanner *pScanner, const ParserState& state); + virtual void Parse(Scanner *pScanner, ParserState& state); virtual void Write(Emitter& out) const; virtual bool IsScalar() const { return true; } diff --git a/src/sequence.cpp b/src/sequence.cpp index 467826f..0f96e27 100644 --- a/src/sequence.cpp +++ b/src/sequence.cpp @@ -59,7 +59,7 @@ namespace YAML return m_data.size(); } - void Sequence::Parse(Scanner *pScanner, const ParserState& state) + void Sequence::Parse(Scanner *pScanner, ParserState& state) { Clear(); @@ -71,10 +71,11 @@ namespace YAML } } - void Sequence::ParseBlock(Scanner *pScanner, const ParserState& state) + void Sequence::ParseBlock(Scanner *pScanner, ParserState& state) { // eat start token pScanner->pop(); + state.PushCollectionType(ParserState::BLOCK_SEQ); while(1) { if(pScanner->empty()) @@ -100,12 +101,15 @@ namespace YAML pNode->Parse(pScanner, state); } + + state.PopCollectionType(ParserState::BLOCK_SEQ); } - void Sequence::ParseFlow(Scanner *pScanner, const ParserState& state) + void Sequence::ParseFlow(Scanner *pScanner, ParserState& state) { // eat start token pScanner->pop(); + state.PushCollectionType(ParserState::FLOW_SEQ); while(1) { if(pScanner->empty()) @@ -129,6 +133,8 @@ namespace YAML 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 diff --git a/src/sequence.h b/src/sequence.h index ad4fde5..49bdc83 100644 --- a/src/sequence.h +++ b/src/sequence.h @@ -26,7 +26,7 @@ namespace YAML virtual Node *GetNode(std::size_t i) const; virtual std::size_t GetSize() const; - virtual void Parse(Scanner *pScanner, const ParserState& state); + virtual void Parse(Scanner *pScanner, ParserState& state); virtual void Write(Emitter& out) const; virtual bool IsSequence() const { return true; } @@ -38,8 +38,8 @@ namespace YAML virtual int Compare(Map *) { return -1; } private: - void ParseBlock(Scanner *pScanner, const ParserState& state); - void ParseFlow(Scanner *pScanner, const ParserState& state); + void ParseBlock(Scanner *pScanner, ParserState& state); + void ParseFlow(Scanner *pScanner, ParserState& state); protected: std::vector m_data; diff --git a/test/parsertests.cpp b/test/parsertests.cpp index 138143c..4c159bc 100644 --- a/test/parsertests.cpp +++ b/test/parsertests.cpp @@ -610,6 +610,28 @@ namespace Test return true; } + + bool BlockKeyWithNullValue() + { + std::string input = + "key:\n" + "just a key: value"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + std::string output; + + parser.GetNextDocument(doc); + if(doc.size() != 2) + return false; + if(!IsNull(doc["key"])) + return false; + if(doc["just a key"] != "value") + return false; + + return true; + } } namespace { @@ -869,6 +891,7 @@ namespace Test RunParserTest(&Parser::MultipleDocs, "multiple docs", passed, total); RunParserTest(&Parser::ExplicitEndDoc, "explicit end doc", passed, total); RunParserTest(&Parser::MultipleDocsWithSomeExplicitIndicators, "multiple docs with some explicit indicators", passed, total); + RunParserTest(&Parser::BlockKeyWithNullValue, "block key with null value", passed, total); RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed, total); RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed, total); From 4dd1b19e51d56de3cc95c1bcc0d4f9f6bd65f0e6 Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 30 Oct 2009 04:52:13 +0000 Subject: [PATCH 206/295] Updated the Visual Studio solution for the new files/renaming. --- parse.vcproj | 190 ++++++++++++++++++++++++++++++ yaml-reader.vcproj => test.vcproj | 34 +++--- yamlcpp.sln | 21 +++- yamlcpp.vcproj | 20 +++- 4 files changed, 241 insertions(+), 24 deletions(-) create mode 100644 parse.vcproj rename yaml-reader.vcproj => test.vcproj (79%) diff --git a/parse.vcproj b/parse.vcproj new file mode 100644 index 0000000..1663a6f --- /dev/null +++ b/parse.vcproj @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/yaml-reader.vcproj b/test.vcproj similarity index 79% rename from yaml-reader.vcproj rename to test.vcproj index 0e550f9..7851a8a 100644 --- a/yaml-reader.vcproj +++ b/test.vcproj @@ -2,9 +2,9 @@ @@ -45,7 +45,7 @@ BasicRuntimeChecks="3" RuntimeLibrary="3" WarningLevel="3" - DebugInformationFormat="3" + DebugInformationFormat="4" /> @@ -194,22 +194,28 @@ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + + diff --git a/yamlcpp.sln b/yamlcpp.sln index 6a0f57f..44da0ab 100644 --- a/yamlcpp.sln +++ b/yamlcpp.sln @@ -1,12 +1,17 @@  Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml-reader", "yaml-reader.vcproj", "{E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yamlcpp", "yamlcpp.vcproj", "{3104AB4E-CD31-4F47-95E9-0E8D9374E15D}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcproj", "{D1108F40-6ADF-467E-A95A-236C39A515C5}" ProjectSection(ProjectDependencies) = postProject {3104AB4E-CD31-4F47-95E9-0E8D9374E15D} = {3104AB4E-CD31-4F47-95E9-0E8D9374E15D} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yamlcpp", "yamlcpp.vcproj", "{3104AB4E-CD31-4F47-95E9-0E8D9374E15D}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "parse", "parse.vcproj", "{CD007B57-7812-4930-A5E2-6E5E56338814}" + ProjectSection(ProjectDependencies) = postProject + {3104AB4E-CD31-4F47-95E9-0E8D9374E15D} = {3104AB4E-CD31-4F47-95E9-0E8D9374E15D} + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -14,14 +19,18 @@ Global Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}.Debug|Win32.ActiveCfg = Debug|Win32 - {E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}.Debug|Win32.Build.0 = Debug|Win32 - {E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}.Release|Win32.ActiveCfg = Release|Win32 - {E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}.Release|Win32.Build.0 = Release|Win32 {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Debug|Win32.ActiveCfg = Debug|Win32 {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Debug|Win32.Build.0 = Debug|Win32 {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Release|Win32.ActiveCfg = Release|Win32 {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Release|Win32.Build.0 = Release|Win32 + {D1108F40-6ADF-467E-A95A-236C39A515C5}.Debug|Win32.ActiveCfg = Debug|Win32 + {D1108F40-6ADF-467E-A95A-236C39A515C5}.Debug|Win32.Build.0 = Debug|Win32 + {D1108F40-6ADF-467E-A95A-236C39A515C5}.Release|Win32.ActiveCfg = Release|Win32 + {D1108F40-6ADF-467E-A95A-236C39A515C5}.Release|Win32.Build.0 = Release|Win32 + {CD007B57-7812-4930-A5E2-6E5E56338814}.Debug|Win32.ActiveCfg = Debug|Win32 + {CD007B57-7812-4930-A5E2-6E5E56338814}.Debug|Win32.Build.0 = Debug|Win32 + {CD007B57-7812-4930-A5E2-6E5E56338814}.Release|Win32.ActiveCfg = Release|Win32 + {CD007B57-7812-4930-A5E2-6E5E56338814}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/yamlcpp.vcproj b/yamlcpp.vcproj index 8673b8f..d22c7a4 100644 --- a/yamlcpp.vcproj +++ b/yamlcpp.vcproj @@ -171,10 +171,6 @@ RelativePath=".\src\aliascontent.cpp" > - - @@ -203,6 +199,10 @@ RelativePath=".\src\sequence.cpp" > + + + + @@ -337,6 +341,10 @@ RelativePath=".\src\sequence.h" > + + + + From a55970c879664fd968942ca6d6e54bc1b830bc79 Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 30 Oct 2009 18:16:26 +0000 Subject: [PATCH 207/295] Added some block scalar tests (with errors) --- test/spectests.cpp | 237 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) diff --git a/test/spectests.cpp b/test/spectests.cpp index 1857234..3cfc25c 100644 --- a/test/spectests.cpp +++ b/test/spectests.cpp @@ -1826,6 +1826,234 @@ namespace Test { } return " no exception thrown"; } + + // 7.23 + TEST FlowContent() + { + std::string input = + "- [ a, b ]\n" + "- { a: b }\n" + "- \"a\"\n" + "- 'b'\n" + "- c"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 5); + YAML_ASSERT(doc[0].size() == 2); + YAML_ASSERT(doc[0][0] == "a"); + YAML_ASSERT(doc[0][1] == "b"); + YAML_ASSERT(doc[1].size() == 1); + YAML_ASSERT(doc[1]["a"] == "b"); + YAML_ASSERT(doc[2] == "a"); + YAML_ASSERT(doc[3] == 'b'); + YAML_ASSERT(doc[4] == "c"); + return true; + } + + // 7.24 + TEST FlowNodes() + { + std::string input = + "- !!str \"a\"\n" + "- 'b'\n" + "- &anchor \"c\"\n" + "- *anchor\n" + "- !!str"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 5); + YAML_ASSERT(doc[0].GetTag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(doc[0] == "a"); + YAML_ASSERT(doc[1] == 'b'); + YAML_ASSERT(doc[2] == "c"); + YAML_ASSERT(doc[3] == "c"); + YAML_ASSERT(doc[4].GetTag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(doc[4] == ""); + return true; + } + + // 8.1 + TEST BlockScalarHeader() + { + std::string input = + "- | # Empty header\n" + " literal\n" + "- >1 # Indentation indicator\n" + " folded\n" + "- |+ # Chomping indicator\n" + " keep\n" + "\n" + "- >1- # Both indicators\n" + " strip\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 4); + YAML_ASSERT(doc[0] == "literal\n"); + YAML_ASSERT(doc[1] == " folded\n"); + YAML_ASSERT(doc[2] == "keep\n\n"); + YAML_ASSERT(doc[3] == " strip"); + return true; + } + + // 8.2 + TEST BlockIndentationHeader() + { + std::string input = + "- |\n" + " detected\n" + "- >\n" + " \n" + " \n" + " # detected\n" + "- |1\n" + " explicit\n" + "- >\n" + " \t\n" + " detected\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 4); + YAML_ASSERT(doc[0] == "detected\n"); + YAML_ASSERT(doc[1] == "\n\n# detected\n"); + YAML_ASSERT(doc[2] == " explicit\n"); + YAML_ASSERT(doc[3] == "\t detected\n"); + return true; + } + + // 8.3 + TEST InvalidBlockScalarIndentationIndicators() + { + { + std::string input = + "- |\n" + " \n" + " text"; + + bool threw = false; + try { + PARSE(doc, input); + } catch(const YAML::Exception& e) { + if(e.msg != YAML::ErrorMsg::END_OF_SEQ) + throw; + + threw = true; + } + + if(!threw) + return " no exception thrown for less indented auto-detecting indentation for a literal block scalar"; + } + + { + std::string input = + "- >\n" + " text\n" + " text"; + + bool threw = false; + try { + PARSE(doc, input); + } catch(const YAML::Exception& e) { + if(e.msg != YAML::ErrorMsg::END_OF_SEQ) + throw; + + threw = true; + } + + if(!threw) + return " no exception thrown for less indented auto-detecting indentation for a folded block scalar"; + } + + { + std::string input = + "- |2\n" + " text"; + + bool threw = false; + try { + PARSE(doc, input); + } catch(const YAML::Exception& e) { + if(e.msg != YAML::ErrorMsg::END_OF_SEQ) + throw; + + threw = true; + } + + if(!threw) + return " no exception thrown for less indented explicit indentation for a literal block scalar"; + } + + return true; + } + + // 8.4 + TEST ChompingFinalLineBreak() + { + std::string input = + "strip: |-\n" + " text\n" + "clip: |\n" + " text\n" + "keep: |+\n" + " text\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["strip"] == "text"); + YAML_ASSERT(doc["clip"] == "text\n"); + YAML_ASSERT(doc["keep"] == "text\n"); + return true; + } + + // 8.5 + TEST ChompingTrailingLines() + { + std::string input = + " # Strip\n" + " # Comments:\n" + "strip: |-\n" + " # text\n" + " \n" + " # Clip\n" + " # comments:\n" + "\n" + "clip: |\n" + " # text\n" + " \n" + " # Keep\n" + " # comments:\n" + "\n" + "keep: |+\n" + " # text\n" + "\n" + " # Trail\n" + " # Comments\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["strip"] == "# text"); + YAML_ASSERT(doc["clip"] == "# text\n"); + YAML_ASSERT(doc["keep"] == "# text\n"); + return true; + } + + // 8.6 + TEST EmptyScalarChomping() + { + std::string input = + "strip: >-\n" + "\n" + "clip: >\n" + "\n" + "keep: |+\n" + "\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["strip"] == ""); + YAML_ASSERT(doc["clip"] == ""); + YAML_ASSERT(doc["keep"] == "\n"); + return true; + } } bool RunSpecTests() @@ -1920,6 +2148,15 @@ namespace Test { RunSpecTest(&Spec::SinglePairExplicitEntry, "7.20", "Single Pair Explicit Entry", passed, total); RunSpecTest(&Spec::SinglePairImplicitEntries, "7.21", "Single Pair Implicit Entries", passed, total); RunSpecTest(&Spec::InvalidImplicitKeys, "7.22", "Invalid Implicit Keys", passed, total); + RunSpecTest(&Spec::FlowContent, "7.23", "Flow Content", passed, total); + RunSpecTest(&Spec::FlowNodes, "7.24", "FlowNodes", passed, total); + + RunSpecTest(&Spec::BlockScalarHeader, "8.1", "Block Scalar Header", passed, total); + RunSpecTest(&Spec::BlockIndentationHeader, "8.2", "Block Indentation Header", passed, total); + RunSpecTest(&Spec::InvalidBlockScalarIndentationIndicators, "8.3", "Invalid Block Scalar Indentation Indicators", passed, total); + RunSpecTest(&Spec::ChompingFinalLineBreak, "8.4", "Chomping Final Line Break", passed, total); + RunSpecTest(&Spec::ChompingTrailingLines, "8.4", "Chomping Trailing Lines", passed, total); + RunSpecTest(&Spec::EmptyScalarChomping, "8.4", "Empty Scalar Chomping", passed, total); std::cout << "Spec tests: " << passed << "/" << total << " passed\n"; return passed == total; From fea35e3e8f3ea9b4081703fc4d3e6f01cf09fec4 Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 30 Oct 2009 20:29:14 +0000 Subject: [PATCH 208/295] Fixed silly bug in node cloning --- src/node.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node.cpp b/src/node.cpp index 198bb71..24d3635 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -27,7 +27,7 @@ namespace YAML 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(m_pContent) + if(pContent) m_pContent = pContent->Clone(); } From ca79c3da7fcf68f13f25f192622ada8523fcd92e Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 4 Nov 2009 22:56:59 +0000 Subject: [PATCH 209/295] Switched the Exp:: regexes to functions that lazily evaluate their regexes --- src/emitterutils.cpp | 16 ++-- src/exp.h | 171 ++++++++++++++++++++++++++++++++++--------- src/scanner.cpp | 26 +++---- src/scanscalar.cpp | 16 ++-- src/scantag.cpp | 8 +- src/scantoken.cpp | 28 +++---- 6 files changed, 182 insertions(+), 83 deletions(-) diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index 202750a..62a7ef3 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -129,7 +129,7 @@ namespace YAML bool IsValidPlainScalar(const std::string& str, bool inFlow, bool allowOnlyAscii) { // first check the start - const RegEx& start = (inFlow ? Exp::PlainScalarInFlow : Exp::PlainScalar); + const RegEx& start = (inFlow ? Exp::PlainScalarInFlow() : Exp::PlainScalar()); if(!start.Matches(str)) return false; @@ -138,12 +138,12 @@ namespace YAML return false; // then check until something is disallowed - const RegEx& disallowed = (inFlow ? Exp::EndScalarInFlow : Exp::EndScalar) - || (Exp::BlankOrBreak + Exp::Comment) - || Exp::NotPrintable - || Exp::Utf8_ByteOrderMark - || Exp::Break - || Exp::Tab; + const RegEx& disallowed = (inFlow ? Exp::EndScalarInFlow() : Exp::EndScalar()) + || (Exp::BlankOrBreak() + Exp::Comment()) + || Exp::NotPrintable() + || Exp::Utf8_ByteOrderMark() + || Exp::Break() + || Exp::Tab(); StringCharSource buffer(str.c_str(), str.size()); while(buffer) { if(disallowed.Matches(buffer)) @@ -299,7 +299,7 @@ namespace YAML out << "!<"; StringCharSource buffer(str.c_str(), str.size()); while(buffer) { - int n = Exp::URI.Match(buffer); + int n = Exp::URI().Match(buffer); if(n <= 0) return false; diff --git a/src/exp.h b/src/exp.h index f8dbc29..acebc18 100644 --- a/src/exp.h +++ b/src/exp.h @@ -17,54 +17,153 @@ namespace YAML namespace Exp { // misc - const RegEx Space = RegEx(' '); - const RegEx Tab = RegEx('\t'); - const RegEx Blank = Space || Tab; - const RegEx Break = RegEx('\n') || RegEx("\r\n"); - const RegEx BlankOrBreak = Blank || Break; - const RegEx Digit = RegEx('0', '9'); - const RegEx Alpha = RegEx('a', 'z') || RegEx('A', 'Z'); - const RegEx AlphaNumeric = Alpha || Digit; - const RegEx Word = AlphaNumeric || RegEx('-'); - const RegEx Hex = Digit || RegEx('A', 'F') || RegEx('a', 'f'); + inline const RegEx& Space() { + static const RegEx e = RegEx(' '); + return e; + } + inline const RegEx& Tab() { + static const RegEx e = RegEx('\t'); + return e; + } + inline const RegEx& Blank() { + static const RegEx e = Space() || Tab(); + return e; + } + inline const RegEx& Break() { + static const RegEx e = RegEx('\n') || RegEx("\r\n"); + return e; + } + inline const RegEx& BlankOrBreak() { + static const RegEx e = Blank() || Break(); + return e; + } + inline const RegEx& Digit() { + static const RegEx e = RegEx('0', '9'); + return e; + } + inline const RegEx& Alpha() { + static const RegEx e = RegEx('a', 'z') || RegEx('A', 'Z'); + return e; + } + inline const RegEx& AlphaNumeric() { + static const RegEx e = Alpha() || Digit(); + return e; + } + inline const RegEx& Word() { + static const RegEx e = AlphaNumeric() || RegEx('-'); + return e; + } + inline const RegEx& Hex() { + static const RegEx e = Digit() || RegEx('A', 'F') || RegEx('a', 'f'); + return e; + } // Valid Unicode code points that are not part of c-printable (YAML 1.2, sec. 5.1) - const RegEx NotPrintable = RegEx(0) || - RegEx("\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x7F", REGEX_OR) || - RegEx(0x0E, 0x1F) || - (RegEx('\xC2') + (RegEx('\x80', '\x84') || RegEx('\x86', '\x9F'))); - const RegEx Utf8_ByteOrderMark = RegEx("\xEF\xBB\xBF"); + inline const RegEx& NotPrintable() { + static const RegEx e = RegEx(0) || + RegEx("\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x7F", REGEX_OR) || + RegEx(0x0E, 0x1F) || + (RegEx('\xC2') + (RegEx('\x80', '\x84') || RegEx('\x86', '\x9F'))); + return e; + } + inline const RegEx& Utf8_ByteOrderMark() { + static const RegEx e = RegEx("\xEF\xBB\xBF"); + return e; + } // actual tags - const RegEx DocStart = RegEx("---") + (BlankOrBreak || RegEx()); - const RegEx DocEnd = RegEx("...") + (BlankOrBreak || RegEx()); - const RegEx DocIndicator = DocStart || DocEnd; - const RegEx BlockEntry = RegEx('-') + (BlankOrBreak || RegEx()); - const RegEx Key = RegEx('?'), - KeyInFlow = RegEx('?') + BlankOrBreak; - const RegEx Value = RegEx(':') + (BlankOrBreak || RegEx()), - ValueInFlow = RegEx(':') + (BlankOrBreak || RegEx(",}", REGEX_OR)), - ValueInJSONFlow = RegEx(':'); - const RegEx Comment = RegEx('#'); - const RegEx AnchorEnd = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak; - const RegEx URI = Word || RegEx("#;/?:@&=+$,_.!~*'()[]", REGEX_OR) || (RegEx('%') + Hex + Hex); - const RegEx Tag = Word || RegEx("#;/?:@&=+$_.~*'", REGEX_OR) || (RegEx('%') + Hex + Hex); + inline const RegEx& DocStart() { + static const RegEx e = RegEx("---") + (BlankOrBreak() || RegEx()); + return e; + } + inline const RegEx& DocEnd() { + static const RegEx e = RegEx("...") + (BlankOrBreak() || RegEx()); + return e; + } + inline const RegEx& DocIndicator() { + static const RegEx e = DocStart || DocEnd; + return e; + } + inline const RegEx& BlockEntry() { + static const RegEx e = RegEx('-') + (BlankOrBreak() || RegEx()); + return e; + } + inline const RegEx& Key() { + static const RegEx e = RegEx('?'); + return e; + } + inline const RegEx& KeyInFlow() { + static const RegEx e = RegEx('?') + BlankOrBreak(); + return e; + } + inline const RegEx& Value() { + static const RegEx e = RegEx(':') + (BlankOrBreak() || RegEx()); + return e; + } + inline const RegEx& ValueInFlow() { + static const RegEx e = RegEx(':') + (BlankOrBreak() || RegEx(",}", REGEX_OR)); + return e; + } + inline const RegEx& ValueInJSONFlow() { + static const RegEx e = RegEx(':'); + return e; + } + inline const RegEx Comment() { + static const RegEx e = RegEx('#'); + return e; + } + inline const RegEx& AnchorEnd() { + static const RegEx e = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak(); + return e; + } + inline const RegEx& URI() { + static const RegEx e = Word() || RegEx("#;/?:@&=+$,_.!~*'()[]", REGEX_OR) || (RegEx('%') + Hex() + Hex()); + return e; + } + inline const RegEx& Tag() { + static const RegEx e = Word() || RegEx("#;/?:@&=+$_.~*'", REGEX_OR) || (RegEx('%') + Hex() + Hex()); + return e; + } // Plain scalar rules: // . Cannot start with a blank. // . Can never start with any of , [ ] { } # & * ! | > \' \" % @ ` // . In the block context - ? : must be not be followed with a space. // . In the flow context ? is illegal and : and - must not be followed with a space. - const RegEx PlainScalar = !(BlankOrBreak || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:", REGEX_OR) + Blank)), - PlainScalarInFlow = !(BlankOrBreak || RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-:", REGEX_OR) + Blank)); - const RegEx EndScalar = RegEx(':') + (BlankOrBreak || RegEx()), - EndScalarInFlow = (RegEx(':') + (BlankOrBreak || RegEx(",]}", REGEX_OR))) || RegEx(",?[]{}", REGEX_OR); + inline const RegEx& PlainScalar() { + static const RegEx e = !(BlankOrBreak() || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:", REGEX_OR) + Blank())); + return e; + } + inline const RegEx& PlainScalarInFlow() { + static const RegEx e = !(BlankOrBreak() || RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-:", REGEX_OR) + Blank())); + return e; + } + inline const RegEx& EndScalar() { + static const RegEx e = RegEx(':') + (BlankOrBreak() || RegEx()); + return e; + } + inline const RegEx& EndScalarInFlow() { + static const RegEx e = (RegEx(':') + (BlankOrBreak() || RegEx(",]}", REGEX_OR))) || RegEx(",?[]{}", REGEX_OR); + return e; + } - const RegEx EscSingleQuote = RegEx("\'\'"); - const RegEx EscBreak = RegEx('\\') + Break; + inline const RegEx& EscSingleQuote() { + static const RegEx e = RegEx("\'\'"); + return e; + } + inline const RegEx& EscBreak() { + static const RegEx e = RegEx('\\') + Break(); + return e; + } - const RegEx ChompIndicator = RegEx("+-", REGEX_OR); - const RegEx Chomp = (ChompIndicator + Digit) || (Digit + ChompIndicator) || ChompIndicator || Digit; + inline const RegEx& ChompIndicator() { + static const RegEx e = RegEx("+-", REGEX_OR); + return e; + } + inline const RegEx& Chomp() { + static const RegEx e = (ChompIndicator() + Digit()) || (Digit() + ChompIndicator()) || ChompIndicator() || Digit(); + return e; + } // and some functions std::string Escape(Stream& in); diff --git a/src/scanner.cpp b/src/scanner.cpp index 13963a4..33052c2 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -119,10 +119,10 @@ namespace YAML return ScanDirective(); // document token - if(INPUT.column() == 0 && Exp::DocStart.Matches(INPUT)) + if(INPUT.column() == 0 && Exp::DocStart().Matches(INPUT)) return ScanDocStart(); - if(INPUT.column() == 0 && Exp::DocEnd.Matches(INPUT)) + if(INPUT.column() == 0 && Exp::DocEnd().Matches(INPUT)) return ScanDocEnd(); // flow start/end/entry @@ -136,10 +136,10 @@ namespace YAML return ScanFlowEntry(); // block/map stuff - if(Exp::BlockEntry.Matches(INPUT)) + if(Exp::BlockEntry().Matches(INPUT)) return ScanBlockEntry(); - if((InBlockContext() ? Exp::Key : Exp::KeyInFlow).Matches(INPUT)) + if((InBlockContext() ? Exp::Key() : Exp::KeyInFlow()).Matches(INPUT)) return ScanKey(); if(GetValueRegex().Matches(INPUT)) @@ -161,7 +161,7 @@ namespace YAML return ScanQuotedScalar(); // plain scalars - if((InBlockContext() ? Exp::PlainScalar : Exp::PlainScalarInFlow).Matches(INPUT)) + if((InBlockContext() ? Exp::PlainScalar() : Exp::PlainScalarInFlow()).Matches(INPUT)) return ScanPlainScalar(); // don't know what it is! @@ -175,24 +175,24 @@ namespace YAML while(1) { // first eat whitespace while(INPUT && IsWhitespaceToBeEaten(INPUT.peek())) { - if(InBlockContext() && Exp::Tab.Matches(INPUT)) + if(InBlockContext() && Exp::Tab().Matches(INPUT)) m_simpleKeyAllowed = false; INPUT.eat(1); } // then eat a comment - if(Exp::Comment.Matches(INPUT)) { + if(Exp::Comment().Matches(INPUT)) { // eat until line break - while(INPUT && !Exp::Break.Matches(INPUT)) + while(INPUT && !Exp::Break().Matches(INPUT)) INPUT.eat(1); } // if it's NOT a line break, then we're done! - if(!Exp::Break.Matches(INPUT)) + if(!Exp::Break().Matches(INPUT)) break; // otherwise, let's eat the line break and keep going - int n = Exp::Break.Match(INPUT); + int n = Exp::Break().Match(INPUT); INPUT.eat(n); // oh yeah, and let's get rid of that simple key @@ -231,9 +231,9 @@ namespace YAML const RegEx& Scanner::GetValueRegex() const { if(InBlockContext()) - return Exp::Value; + return Exp::Value(); - return m_canBeJSONFlow ? Exp::ValueInJSONFlow : Exp::ValueInFlow; + return m_canBeJSONFlow ? Exp::ValueInJSONFlow() : Exp::ValueInFlow(); } // StartStream @@ -323,7 +323,7 @@ namespace YAML const IndentMarker& indent = *m_indents.top(); if(indent.column < INPUT.column()) break; - if(indent.column == INPUT.column() && !(indent.type == IndentMarker::SEQ && !Exp::BlockEntry.Matches(INPUT))) + if(indent.column == INPUT.column() && !(indent.type == IndentMarker::SEQ && !Exp::BlockEntry().Matches(INPUT))) break; PopIndent(); diff --git a/src/scanscalar.cpp b/src/scanscalar.cpp index f7f3519..50b8bf7 100644 --- a/src/scanscalar.cpp +++ b/src/scanscalar.cpp @@ -32,12 +32,12 @@ namespace YAML std::size_t lastNonWhitespaceChar = scalar.size(); bool escapedNewline = false; - while(!params.end.Matches(INPUT) && !Exp::Break.Matches(INPUT)) { + while(!params.end.Matches(INPUT) && !Exp::Break().Matches(INPUT)) { if(!INPUT) break; // document indicator? - if(INPUT.column() == 0 && Exp::DocIndicator.Matches(INPUT)) { + if(INPUT.column() == 0 && Exp::DocIndicator().Matches(INPUT)) { if(params.onDocIndicator == BREAK) break; else if(params.onDocIndicator == THROW) @@ -48,7 +48,7 @@ namespace YAML pastOpeningBreak = true; // escaped newline? (only if we're escaping on slash) - if(params.escape == '\\' && Exp::EscBreak.Matches(INPUT)) { + if(params.escape == '\\' && Exp::EscBreak().Matches(INPUT)) { // eat escape character and get out (but preserve trailing whitespace!) INPUT.get(); lastNonWhitespaceChar = scalar.size(); @@ -78,7 +78,7 @@ namespace YAML } // doc indicator? - if(params.onDocIndicator == BREAK && INPUT.column() == 0 && Exp::DocIndicator.Matches(INPUT)) + if(params.onDocIndicator == BREAK && INPUT.column() == 0 && Exp::DocIndicator().Matches(INPUT)) break; // are we done via character match? @@ -95,7 +95,7 @@ namespace YAML // ******************************** // Phase #2: eat line ending - n = Exp::Break.Match(INPUT); + n = Exp::Break().Match(INPUT); INPUT.eat(n); // ******************************** @@ -110,7 +110,7 @@ namespace YAML params.indent = std::max(params.indent, INPUT.column()); // and then the rest of the whitespace - while(Exp::Blank.Matches(INPUT)) { + while(Exp::Blank().Matches(INPUT)) { // we check for tabs that masquerade as indentation if(INPUT.peek() == '\t'&& INPUT.column() < params.indent && params.onTabInIndentation == THROW) throw ParserException(INPUT.mark(), ErrorMsg::TAB_IN_INDENTATION); @@ -122,8 +122,8 @@ namespace YAML } // was this an empty line? - bool nextEmptyLine = Exp::Break.Matches(INPUT); - bool nextMoreIndented = Exp::Blank.Matches(INPUT); + bool nextEmptyLine = Exp::Break().Matches(INPUT); + bool nextMoreIndented = Exp::Blank().Matches(INPUT); if(params.fold == FOLD_BLOCK && foldedNewlineCount == 0 && nextEmptyLine) foldedNewlineStartedMoreIndented = moreIndented; diff --git a/src/scantag.cpp b/src/scantag.cpp index 17a6d65..f08218e 100644 --- a/src/scantag.cpp +++ b/src/scantag.cpp @@ -19,7 +19,7 @@ namespace YAML return tag; } - int n = Exp::URI.Match(INPUT); + int n = Exp::URI().Match(INPUT); if(n <= 0) break; @@ -44,7 +44,7 @@ namespace YAML int n = 0; if(canBeHandle) { - n = Exp::Word.Match(INPUT); + n = Exp::Word().Match(INPUT); if(n <= 0) { canBeHandle = false; firstNonWordChar = INPUT.mark(); @@ -52,7 +52,7 @@ namespace YAML } if(!canBeHandle) - n = Exp::Tag.Match(INPUT); + n = Exp::Tag().Match(INPUT); if(n <= 0) break; @@ -68,7 +68,7 @@ namespace YAML std::string tag; while(INPUT) { - int n = Exp::Tag.Match(INPUT); + int n = Exp::Tag().Match(INPUT); if(n <= 0) break; diff --git a/src/scantoken.cpp b/src/scantoken.cpp index 4320364..3e7e1cc 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -31,22 +31,22 @@ namespace YAML INPUT.eat(1); // read name - while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) + while(INPUT && !Exp::BlankOrBreak().Matches(INPUT)) token.value += INPUT.get(); // read parameters while(1) { // first get rid of whitespace - while(Exp::Blank.Matches(INPUT)) + while(Exp::Blank().Matches(INPUT)) INPUT.eat(1); // break on newline or comment - if(!INPUT || Exp::Break.Matches(INPUT) || Exp::Comment.Matches(INPUT)) + if(!INPUT || Exp::Break().Matches(INPUT) || Exp::Comment().Matches(INPUT)) break; // now read parameter std::string param; - while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) + while(INPUT && !Exp::BlankOrBreak().Matches(INPUT)) param += INPUT.get(); token.params.push_back(param); @@ -238,7 +238,7 @@ namespace YAML alias = (indicator == Keys::Alias); // now eat the content - while(Exp::AlphaNumeric.Matches(INPUT)) + while(Exp::AlphaNumeric().Matches(INPUT)) name += INPUT.get(); // we need to have read SOMETHING! @@ -246,7 +246,7 @@ namespace YAML throw ParserException(INPUT.mark(), alias ? ErrorMsg::ALIAS_NOT_FOUND : ErrorMsg::ANCHOR_NOT_FOUND); // and needs to end correctly - if(INPUT && !Exp::AnchorEnd.Matches(INPUT)) + if(INPUT && !Exp::AnchorEnd().Matches(INPUT)) throw ParserException(INPUT.mark(), alias ? ErrorMsg::CHAR_IN_ALIAS : ErrorMsg::CHAR_IN_ANCHOR); // and we're done @@ -297,7 +297,7 @@ namespace YAML // set up the scanning parameters ScanScalarParams params; - params.end = (InFlowContext() ? Exp::EndScalarInFlow : Exp::EndScalar) || (Exp::BlankOrBreak + Exp::Comment); + params.end = (InFlowContext() ? Exp::EndScalarInFlow() : Exp::EndScalar()) || (Exp::BlankOrBreak() + Exp::Comment()); params.eatEnd = false; params.indent = (InFlowContext() ? 0 : GetTopIndent() + 1); params.fold = FOLD_FLOW; @@ -337,7 +337,7 @@ namespace YAML // setup the scanning parameters ScanScalarParams params; - params.end = (single ? RegEx(quote) && !Exp::EscSingleQuote : RegEx(quote)); + params.end = (single ? RegEx(quote) && !Exp::EscSingleQuote() : RegEx(quote)); params.eatEnd = true; params.escape = (single ? '\'' : '\\'); params.indent = 0; @@ -384,14 +384,14 @@ namespace YAML // eat chomping/indentation indicators params.chomp = CLIP; - int n = Exp::Chomp.Match(INPUT); + int n = Exp::Chomp().Match(INPUT); for(int i=0;i Date: Fri, 6 Nov 2009 03:13:54 +0000 Subject: [PATCH 210/295] Fixed the return value of the integral conversion functions, and also unset the dec flag so it reads other bases (just a temporary fix, since we're officially supposed to read binary too) --- include/conversion.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/conversion.h b/include/conversion.h index dfaf9f2..a1aadce 100644 --- a/include/conversion.h +++ b/include/conversion.h @@ -21,8 +21,8 @@ namespace YAML #define YAML_MAKE_STREAM_CONVERT(type) \ inline bool Convert(const std::string& input, type& output) { \ std::stringstream stream(input); \ - stream >> output; \ - return !stream.fail(); \ + stream.unsetf(std::ios::dec); \ + return stream >> output; \ } YAML_MAKE_STREAM_CONVERT(char) From 71489e5abfb1ae0d63294759cdab855fa62a95ed Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 6 Nov 2009 03:24:12 +0000 Subject: [PATCH 211/295] Overloaded more integral types for emitting --- include/emitter.h | 27 ++++++++++++++++++++++++++- src/emitter.cpp | 18 +++++++----------- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/include/emitter.h b/include/emitter.h index c13b9cc..259d899 100644 --- a/include/emitter.h +++ b/include/emitter.h @@ -46,7 +46,12 @@ namespace YAML // overloads of write Emitter& Write(const std::string& str); Emitter& Write(const char *str); - Emitter& Write(int i); + Emitter& Write(int value) { return WriteIntegralType(value); } + Emitter& Write(unsigned int value) { return WriteIntegralType(value); } + Emitter& Write(short value) { return WriteIntegralType(value); } + Emitter& Write(unsigned short value) { return WriteIntegralType(value); } + Emitter& Write(long value) { return WriteIntegralType(value); } + Emitter& Write(unsigned long value) { return WriteIntegralType(value); } Emitter& Write(bool b); Emitter& Write(float f); Emitter& Write(double d); @@ -56,6 +61,13 @@ namespace YAML Emitter& Write(const _Comment& comment); Emitter& Write(const _Null& null); + private: + void PreWriteIntegralType(std::stringstream& str); + void PostWriteIntegralType(const std::stringstream& str); + + template + Emitter& WriteIntegralType(T value); + private: enum ATOMIC_TYPE { AT_SCALAR, AT_SEQ, AT_BLOCK_SEQ, AT_FLOW_SEQ, AT_MAP, AT_BLOCK_MAP, AT_FLOW_MAP }; @@ -76,6 +88,19 @@ namespace YAML std::auto_ptr m_pState; }; + template + inline Emitter& Emitter::WriteIntegralType(T value) + { + if(!good()) + return *this; + + std::stringstream str; + PreWriteIntegralType(str); + str << value; + PostWriteIntegralType(str); + return *this; + } + // overloads of insertion template inline Emitter& operator << (Emitter& emitter, T v) { diff --git a/src/emitter.cpp b/src/emitter.cpp index e987ad0..bb5f80b 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -556,17 +556,13 @@ namespace YAML return Write(std::string(str)); } - - Emitter& Emitter::Write(int i) + + void Emitter::PreWriteIntegralType(std::stringstream& str) { - if(!good()) - return *this; - PreAtomicWrite(); EmitSeparationIfNecessary(); EMITTER_MANIP intFmt = m_pState->GetIntFormat(); - std::stringstream str; switch(intFmt) { case Dec: str << std::dec; @@ -574,18 +570,18 @@ namespace YAML case Hex: str << std::hex; break; - case Oct: + case Oct: str << std::oct; break; default: assert(false); } - - str << i; + } + + void Emitter::PostWriteIntegralType(const std::stringstream& str) + { m_stream << str.str(); - PostAtomicWrite(); - return *this; } Emitter& Emitter::Write(bool b) From 63cc5adefd0e9f00b0ee0592cddb45a2ea1533c7 Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 10 Nov 2009 21:23:52 +0000 Subject: [PATCH 212/295] Replaced conversion macros with SFINAE --- CMakeLists.txt | 2 +- include/conversion.h | 50 +++++++++++++++++++++++++++----------------- test/parsertests.cpp | 30 ++++++++++++++++++++++++-- 3 files changed, 60 insertions(+), 22 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ab7746..9f21473 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ if(IPHONE) endif(IPHONE) if(CMAKE_COMPILER_IS_GNUCC) - set(CMAKE_CXX_FLAGS "-O2 -Wall -pedantic -Wextra ${CMAKE_CXX_FLAGS}") + set(CMAKE_CXX_FLAGS "-O2 -Wall -Wextra -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}") endif(CMAKE_COMPILER_IS_GNUCC) set(YAML_CPP_VERSION_MAJOR "0") diff --git a/include/conversion.h b/include/conversion.h index a1aadce..4cb0803 100644 --- a/include/conversion.h +++ b/include/conversion.h @@ -18,26 +18,38 @@ namespace YAML bool Convert(const std::string& input, bool& output); bool Convert(const std::string& input, _Null& output); -#define YAML_MAKE_STREAM_CONVERT(type) \ - inline bool Convert(const std::string& input, type& output) { \ - std::stringstream stream(input); \ - stream.unsetf(std::ios::dec); \ - return stream >> output; \ + template + struct is_numeric { enum { value = false }; }; + + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + + + template + struct enable_if; + + template + struct enable_if { + typedef R type; + }; + + template + inline bool Convert(const std::string& input, T& output, typename enable_if, T>::type * = 0) { + std::stringstream stream(input); + stream.unsetf(std::ios::dec); + return stream >> output; } - - YAML_MAKE_STREAM_CONVERT(char) - YAML_MAKE_STREAM_CONVERT(unsigned char) - YAML_MAKE_STREAM_CONVERT(int) - YAML_MAKE_STREAM_CONVERT(unsigned int) - YAML_MAKE_STREAM_CONVERT(short) - YAML_MAKE_STREAM_CONVERT(unsigned short) - YAML_MAKE_STREAM_CONVERT(long) - YAML_MAKE_STREAM_CONVERT(unsigned long) - YAML_MAKE_STREAM_CONVERT(float) - YAML_MAKE_STREAM_CONVERT(double) - YAML_MAKE_STREAM_CONVERT(long double) - -#undef YAML_MAKE_STREAM_CONVERT } #endif // CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/test/parsertests.cpp b/test/parsertests.cpp index 4c159bc..6bf8642 100644 --- a/test/parsertests.cpp +++ b/test/parsertests.cpp @@ -118,7 +118,7 @@ namespace Test inputScalar = "http://example.com/foo#bar"; desiredOutput = "http://example.com/foo#bar"; } - + bool SimpleSeq() { std::string input = @@ -620,7 +620,6 @@ namespace Test std::stringstream stream(input); YAML::Parser parser(stream); YAML::Node doc; - std::string output; parser.GetNextDocument(doc); if(doc.size() != 2) @@ -632,6 +631,32 @@ namespace Test return true; } + + bool Bases() + { + std::string input = + "- 15\n" + "- 0x10\n" + "- 030\n" + "- 0xffffffff\n"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + + parser.GetNextDocument(doc); + if(doc.size() != 4) + return false; + if(doc[0] != 15) + return false; + if(doc[1] != 0x10) + return false; + if(doc[2] != 030) + return false; + if(doc[3] != 0xffffffff) + return false; + return true; + } } namespace { @@ -892,6 +917,7 @@ namespace Test RunParserTest(&Parser::ExplicitEndDoc, "explicit end doc", passed, total); RunParserTest(&Parser::MultipleDocsWithSomeExplicitIndicators, "multiple docs with some explicit indicators", passed, total); RunParserTest(&Parser::BlockKeyWithNullValue, "block key with null value", passed, total); + RunParserTest(&Parser::Bases, "bases", passed, total); RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed, total); RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed, total); From 7b33c7c4b43f5ebb3364e34032938137ec747720 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 12 Nov 2009 05:45:47 +0000 Subject: [PATCH 213/295] Small bug from switching static initialized regexes to lazy ones --- src/exp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/exp.h b/src/exp.h index acebc18..8b84214 100644 --- a/src/exp.h +++ b/src/exp.h @@ -81,7 +81,7 @@ namespace YAML return e; } inline const RegEx& DocIndicator() { - static const RegEx e = DocStart || DocEnd; + static const RegEx e = DocStart() || DocEnd(); return e; } inline const RegEx& BlockEntry() { From bbf510d6cc7fe803f35fc354b6d218031c37dae3 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 12 Nov 2009 17:00:12 +0000 Subject: [PATCH 214/295] Refactored the traits a bit, and added displaying the key to string and numeric key not found errors --- include/conversion.h | 29 ++----------------------- include/exceptions.h | 30 ++++++++++++++++++++------ include/traits.h | 50 ++++++++++++++++++++++++++++++++++++++++++++ test/parsertests.cpp | 35 ++++++++++++++++++++++++++++++- 4 files changed, 110 insertions(+), 34 deletions(-) create mode 100644 include/traits.h diff --git a/include/conversion.h b/include/conversion.h index 4cb0803..13add1c 100644 --- a/include/conversion.h +++ b/include/conversion.h @@ -5,6 +5,7 @@ #include "null.h" +#include "traits.h" #include #include @@ -18,34 +19,8 @@ namespace YAML bool Convert(const std::string& input, bool& output); bool Convert(const std::string& input, _Null& output); - template - struct is_numeric { enum { value = false }; }; - - template <> struct is_numeric { enum { value = true }; }; - template <> struct is_numeric { enum { value = true }; }; - template <> struct is_numeric { enum { value = true }; }; - template <> struct is_numeric { enum { value = true }; }; - template <> struct is_numeric { enum { value = true }; }; - template <> struct is_numeric { enum { value = true }; }; - template <> struct is_numeric { enum { value = true }; }; - template <> struct is_numeric { enum { value = true }; }; - template <> struct is_numeric { enum { value = true }; }; - template <> struct is_numeric { enum { value = true }; }; - template <> struct is_numeric { enum { value = true }; }; - template <> struct is_numeric { enum { value = true }; }; - template <> struct is_numeric { enum { value = true }; }; - - - template - struct enable_if; - - template - struct enable_if { - typedef R type; - }; - template - inline bool Convert(const std::string& input, T& output, typename enable_if, T>::type * = 0) { + inline bool Convert(const std::string& input, T& output, typename enable_if >::type * = 0) { std::stringstream stream(input); stream.unsetf(std::ios::dec); return stream >> output; diff --git a/include/exceptions.h b/include/exceptions.h index 2a9c1d1..f81db59 100644 --- a/include/exceptions.h +++ b/include/exceptions.h @@ -5,6 +5,7 @@ #include "mark.h" +#include "traits.h" #include #include #include @@ -67,6 +68,22 @@ namespace YAML const std::string EXPECTED_VALUE_TOKEN = "expected value token"; const std::string UNEXPECTED_KEY_TOKEN = "unexpected key token"; const std::string UNEXPECTED_VALUE_TOKEN = "unexpected value token"; + + template + inline const std::string KEY_NOT_FOUND_WITH_KEY(const T&, typename disable_if >::type * = 0) { + return KEY_NOT_FOUND; + } + + inline const std::string KEY_NOT_FOUND_WITH_KEY(const std::string& key) { + return KEY_NOT_FOUND + ": " + key; + } + + template + inline const std::string KEY_NOT_FOUND_WITH_KEY(const T& key, typename enable_if >::type * = 0) { + std::stringstream stream; + stream << KEY_NOT_FOUND << ": " << key; + return stream.str(); + } } class Exception: public std::exception { @@ -108,22 +125,23 @@ namespace YAML class KeyNotFound: public RepresentationException { public: - KeyNotFound(const Mark& mark_) - : RepresentationException(mark_, ErrorMsg::KEY_NOT_FOUND) {} + template + KeyNotFound(const Mark& mark_, const T& key_) + : RepresentationException(mark_, ErrorMsg::KEY_NOT_FOUND_WITH_KEY(key_)) {} }; - + template class TypedKeyNotFound: public KeyNotFound { public: TypedKeyNotFound(const Mark& mark_, const T& key_) - : KeyNotFound(mark_), key(key_) {} - ~TypedKeyNotFound() throw() {} + : KeyNotFound(mark_, key_), key(key_) {} + virtual ~TypedKeyNotFound() throw() {} T key; }; template - TypedKeyNotFound MakeTypedKeyNotFound(const Mark& mark, const T& key) { + inline TypedKeyNotFound MakeTypedKeyNotFound(const Mark& mark, const T& key) { return TypedKeyNotFound (mark, key); } diff --git a/include/traits.h b/include/traits.h new file mode 100644 index 0000000..46db01b --- /dev/null +++ b/include/traits.h @@ -0,0 +1,50 @@ +#pragma once + +#ifndef TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + +namespace YAML +{ + template + struct is_numeric { enum { value = false }; }; + + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; + + template + struct enable_if_c { + typedef T type; + }; + + template + struct enable_if_c {}; + + template + struct enable_if : public enable_if_c {}; + + template + struct disable_if_c { + typedef T type; + }; + + template + struct disable_if_c {}; + + template + struct disable_if : public disable_if_c {}; +} + +#endif // TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + diff --git a/test/parsertests.cpp b/test/parsertests.cpp index 6bf8642..d30ed02 100644 --- a/test/parsertests.cpp +++ b/test/parsertests.cpp @@ -657,6 +657,38 @@ namespace Test return false; return true; } + + bool KeyNotFound() + { + std::string input = "key: value"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + try { + doc["bad key"]; + } catch(const YAML::Exception& e) { + if(e.msg != YAML::ErrorMsg::KEY_NOT_FOUND + ": bad key") + throw; + } + + try { + doc[5]; + } catch(const YAML::Exception& e) { + if(e.msg != YAML::ErrorMsg::KEY_NOT_FOUND + ": 5") + throw; + } + + try { + doc[2.5]; + } catch(const YAML::Exception& e) { + if(e.msg != YAML::ErrorMsg::KEY_NOT_FOUND + ": 2.5") + throw; + } + + return true; + } } namespace { @@ -674,7 +706,7 @@ namespace Test doc >> output; } catch(const YAML::Exception& e) { ok = false; - error = e.msg; + error = e.what(); } if(ok && output == desiredOutput) { passed++; @@ -918,6 +950,7 @@ namespace Test RunParserTest(&Parser::MultipleDocsWithSomeExplicitIndicators, "multiple docs with some explicit indicators", passed, total); RunParserTest(&Parser::BlockKeyWithNullValue, "block key with null value", passed, total); RunParserTest(&Parser::Bases, "bases", passed, total); + RunParserTest(&Parser::KeyNotFound, "key not found", passed, total); RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed, total); RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed, total); From 8f0f0d62a7c81ba6dda18a67adc6f21440a05b18 Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 17 Nov 2009 20:21:22 +0000 Subject: [PATCH 215/295] Refactored emitter operator << overloads to not template them, so it's easier to overload for pointer types --- include/emitter.h | 61 +++++++++++++++++++++++++----------- src/emitter.cpp | 40 ------------------------ test/emittertests.cpp | 72 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+), 58 deletions(-) diff --git a/include/emitter.h b/include/emitter.h index 259d899..a353e71 100644 --- a/include/emitter.h +++ b/include/emitter.h @@ -9,6 +9,7 @@ #include "null.h" #include #include +#include namespace YAML { @@ -45,29 +46,23 @@ namespace YAML // overloads of write Emitter& Write(const std::string& str); - Emitter& Write(const char *str); - Emitter& Write(int value) { return WriteIntegralType(value); } - Emitter& Write(unsigned int value) { return WriteIntegralType(value); } - Emitter& Write(short value) { return WriteIntegralType(value); } - Emitter& Write(unsigned short value) { return WriteIntegralType(value); } - Emitter& Write(long value) { return WriteIntegralType(value); } - Emitter& Write(unsigned long value) { return WriteIntegralType(value); } Emitter& Write(bool b); - Emitter& Write(float f); - Emitter& Write(double d); Emitter& Write(const _Alias& alias); Emitter& Write(const _Anchor& anchor); Emitter& Write(const _Tag& tag); Emitter& Write(const _Comment& comment); Emitter& Write(const _Null& null); + template + Emitter& WriteIntegralType(T value); + + template + Emitter& WriteStreamable(T value); + private: void PreWriteIntegralType(std::stringstream& str); void PostWriteIntegralType(const std::stringstream& str); - template - Emitter& WriteIntegralType(T value); - private: enum ATOMIC_TYPE { AT_SCALAR, AT_SEQ, AT_BLOCK_SEQ, AT_FLOW_SEQ, AT_MAP, AT_BLOCK_MAP, AT_FLOW_MAP }; @@ -100,19 +95,49 @@ namespace YAML PostWriteIntegralType(str); return *this; } + + template + inline Emitter& Emitter::WriteStreamable(T value) + { + if(!good()) + return *this; + + PreAtomicWrite(); + EmitSeparationIfNecessary(); + + std::stringstream str; + str << value; + m_stream << str.str(); + + PostAtomicWrite(); + return *this; + } // overloads of insertion - template - inline Emitter& operator << (Emitter& emitter, T v) { - return emitter.Write(v); - } + inline Emitter& operator << (Emitter& emitter, const std::string& v) { return emitter.Write(v); } + inline Emitter& operator << (Emitter& emitter, bool v) { return emitter.Write(v); } + inline Emitter& operator << (Emitter& emitter, const _Alias& v) { return emitter.Write(v); } + inline Emitter& operator << (Emitter& emitter, const _Anchor& v) { return emitter.Write(v); } + inline Emitter& operator << (Emitter& emitter, const _Tag& v) { return emitter.Write(v); } + inline Emitter& operator << (Emitter& emitter, const _Comment& v) { return emitter.Write(v); } + inline Emitter& operator << (Emitter& emitter, const _Null& v) { return emitter.Write(v); } + + inline Emitter& operator << (Emitter& emitter, const char *v) { return emitter.Write(std::string(v)); } + + inline Emitter& operator << (Emitter& emitter, int v) { return emitter.WriteIntegralType(v); } + inline Emitter& operator << (Emitter& emitter, unsigned int v) { return emitter.WriteIntegralType(v); } + inline Emitter& operator << (Emitter& emitter, short v) { return emitter.WriteIntegralType(v); } + inline Emitter& operator << (Emitter& emitter, unsigned short v) { return emitter.WriteIntegralType(v); } + inline Emitter& operator << (Emitter& emitter, long v) { return emitter.WriteIntegralType(v); } + inline Emitter& operator << (Emitter& emitter, unsigned long v) { return emitter.WriteIntegralType(v); } + + inline Emitter& operator << (Emitter& emitter, float v) { return emitter.WriteStreamable(v); } + inline Emitter& operator << (Emitter& emitter, double v) { return emitter.WriteStreamable(v); } - template <> inline Emitter& operator << (Emitter& emitter, EMITTER_MANIP value) { return emitter.SetLocalValue(value); } - template <> inline Emitter& operator << (Emitter& emitter, _Indent indent) { return emitter.SetLocalIndent(indent); } diff --git a/src/emitter.cpp b/src/emitter.cpp index bb5f80b..675fcf8 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -549,14 +549,6 @@ namespace YAML return *this; } - Emitter& Emitter::Write(const char *str) - { - if(!good()) - return *this; - - return Write(std::string(str)); - } - void Emitter::PreWriteIntegralType(std::stringstream& str) { PreAtomicWrite(); @@ -623,38 +615,6 @@ namespace YAML return *this; } - Emitter& Emitter::Write(float f) - { - if(!good()) - return *this; - - PreAtomicWrite(); - EmitSeparationIfNecessary(); - - std::stringstream str; - str << f; - m_stream << str.str(); - - PostAtomicWrite(); - return *this; - } - - Emitter& Emitter::Write(double d) - { - if(!good()) - return *this; - - PreAtomicWrite(); - EmitSeparationIfNecessary(); - - std::stringstream str; - str << d; - m_stream << str.str(); - - PostAtomicWrite(); - return *this; - } - Emitter& Emitter::Write(const _Alias& alias) { if(!good()) diff --git a/test/emittertests.cpp b/test/emittertests.cpp index fa0ef5c..58c3d92 100644 --- a/test/emittertests.cpp +++ b/test/emittertests.cpp @@ -558,6 +558,74 @@ namespace Test desiredOutput = "--- \"\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2\""; } + struct Foo { + Foo(): x(0) {} + Foo(int x_, const std::string& bar_): x(x_), bar(bar_) {} + + int x; + std::string bar; + }; + + YAML::Emitter& operator << (YAML::Emitter& out, const Foo& foo) { + out << YAML::BeginMap; + out << YAML::Key << "x" << YAML::Value << foo.x; + out << YAML::Key << "bar" << YAML::Value << foo.bar; + out << YAML::EndMap; + return out; + } + + void UserType(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << Foo(5, "hello"); + out << Foo(3, "goodbye"); + out << YAML::EndSeq; + + desiredOutput = "---\n-\n x: 5\n bar: hello\n-\n x: 3\n bar: goodbye"; + } + + void UserTypeInContainer(YAML::Emitter& out, std::string& desiredOutput) + { + std::vector fv; + fv.push_back(Foo(5, "hello")); + fv.push_back(Foo(3, "goodbye")); + out << fv; + + desiredOutput = "---\n-\n x: 5\n bar: hello\n-\n x: 3\n bar: goodbye"; + } + + template + YAML::Emitter& operator << (YAML::Emitter& out, const T *v) { + if(v) + out << *v; + else + out << YAML::Null; + return out; + } + + void PointerToInt(YAML::Emitter& out, std::string& desiredOutput) + { + int foo = 5; + int *bar = &foo; + int *baz = 0; + out << YAML::BeginSeq; + out << bar << baz; + out << YAML::EndSeq; + + desiredOutput = "---\n- 5\n- ~"; + } + + void PointerToUserType(YAML::Emitter& out, std::string& desiredOutput) + { + Foo foo(5, "hello"); + Foo *bar = &foo; + Foo *baz = 0; + out << YAML::BeginSeq; + out << bar << baz; + out << YAML::EndSeq; + + desiredOutput = "---\n-\n x: 5\n bar: hello\n- ~"; + } //////////////////////////////////////////////////////////////////////////////////////////////////////// // incorrect emitting @@ -733,6 +801,10 @@ namespace Test RunEmitterTest(&Emitter::EscapedUnicode, "escaped unicode", passed, total); RunEmitterTest(&Emitter::Unicode, "unicode", passed, total); RunEmitterTest(&Emitter::DoubleQuotedUnicode, "double quoted unicode", passed, total); + RunEmitterTest(&Emitter::UserType, "user type", passed, total); + RunEmitterTest(&Emitter::UserTypeInContainer, "user type in container", passed, total); + RunEmitterTest(&Emitter::PointerToInt, "pointer to int", passed, total); + RunEmitterTest(&Emitter::PointerToUserType, "pointer to user type", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total); From f4b81e734978c4797d4ee24f08b9d6ad6d886b51 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 2 Dec 2009 01:01:45 +0000 Subject: [PATCH 216/295] Fixed leak when adding duplicate keys (and actually changed the behavior - now we take the first instance, not the last) --- src/map.cpp | 25 +++++++++++++++---------- src/map.h | 2 ++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/map.cpp b/src/map.cpp index 3a6a299..9ab40c2 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -17,7 +17,7 @@ namespace YAML for(node_map::const_iterator it=data.begin();it!=data.end();++it) { std::auto_ptr pKey = it->first->Clone(); std::auto_ptr pValue = it->second->Clone(); - m_data[pKey.release()] = pValue.release(); + AddEntry(pKey, pValue); } } @@ -104,8 +104,7 @@ namespace YAML pValue->Parse(pScanner, state); } - // assign the map with the actual pointers - m_data[pKey.release()] = pValue.release(); + AddEntry(pKey, pValue); } state.PopCollectionType(ParserState::BLOCK_MAP); @@ -149,8 +148,7 @@ namespace YAML else if(nextToken.type != Token::FLOW_MAP_END) throw ParserException(nextToken.mark, ErrorMsg::END_OF_MAP_FLOW); - // assign the map with the actual pointers - m_data[pKey.release()] = pValue.release(); + AddEntry(pKey, pValue); } state.PopCollectionType(ParserState::FLOW_MAP); @@ -173,8 +171,7 @@ namespace YAML pValue->Parse(pScanner, state); } - // assign the map with the actual pointers - m_data[pKey.release()] = pValue.release(); + AddEntry(pKey, pValue); state.PopCollectionType(ParserState::COMPACT_MAP); } @@ -188,12 +185,20 @@ namespace YAML // grab value pScanner->pop(); pValue->Parse(pScanner, state); - - // assign the map with the actual pointers - m_data[pKey.release()] = pValue.release(); + + AddEntry(pKey, pValue); state.PopCollectionType(ParserState::COMPACT_MAP); } + void Map::AddEntry(std::auto_ptr pKey, std::auto_ptr pValue) + { + node_map::const_iterator it = m_data.find(pKey.get()); + if(it != m_data.end()) + return; + + m_data[pKey.release()] = pValue.release(); + } + void Map::Write(Emitter& out) const { out << BeginMap; diff --git a/src/map.h b/src/map.h index bb8f949..bcfae4b 100644 --- a/src/map.h +++ b/src/map.h @@ -43,6 +43,8 @@ namespace YAML void ParseFlow(Scanner *pScanner, ParserState& state); void ParseCompact(Scanner *pScanner, ParserState& state); void ParseCompactWithNoKey(Scanner *pScanner, ParserState& state); + + void AddEntry(std::auto_ptr pKey, std::auto_ptr pValue); private: node_map m_data; From ac3d95f499868d635ea69f25043a6eec7789afe0 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 2 Dec 2009 01:29:16 +0000 Subject: [PATCH 217/295] Added test for duplicate key --- test/parsertests.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/parsertests.cpp b/test/parsertests.cpp index d30ed02..47b1d8b 100644 --- a/test/parsertests.cpp +++ b/test/parsertests.cpp @@ -689,6 +689,23 @@ namespace Test return true; } + + bool DuplicateKey() + { + std::string input = "{a: 1, b: 2, c: 3, a: 4}"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + if(doc["a"] != 1) + return false; + if(doc["b"] != 2) + return false; + if(doc["c"] != 3) + return false; + return true; + } } namespace { @@ -951,6 +968,7 @@ namespace Test RunParserTest(&Parser::BlockKeyWithNullValue, "block key with null value", passed, total); RunParserTest(&Parser::Bases, "bases", passed, total); RunParserTest(&Parser::KeyNotFound, "key not found", passed, total); + RunParserTest(&Parser::DuplicateKey, "duplicate key", passed, total); RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed, total); RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed, total); From 6d37c370baf83b4aca79640a5545aaa2f21324c6 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 2 Dec 2009 05:59:18 +0000 Subject: [PATCH 218/295] Added missing include --- src/map.cpp | 1 - src/map.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/src/map.cpp b/src/map.cpp index 9ab40c2..2db38b9 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -4,7 +4,6 @@ #include "token.h" #include "exceptions.h" #include "emitter.h" -#include namespace YAML { diff --git a/src/map.h b/src/map.h index bcfae4b..6887880 100644 --- a/src/map.h +++ b/src/map.h @@ -6,6 +6,7 @@ #include "content.h" #include +#include namespace YAML { From 3720ceb57b6d8ae8c7b49c1fb97d95d23f73dfba Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 21 Dec 2009 20:35:27 +0000 Subject: [PATCH 219/295] Added newline to install and license files --- install.txt | 2 +- license.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/install.txt b/install.txt index 74bba87..9392362 100644 --- a/install.txt +++ b/install.txt @@ -21,4 +21,4 @@ make install If you don't want to use CMake, just add all .cpp files to a makefile. yaml-cpp does not need any special build settings, so no 'configure' file is necessary. -(Note: this is pretty tedious. It's sooo much easier to use CMake.) \ No newline at end of file +(Note: this is pretty tedious. It's sooo much easier to use CMake.) diff --git a/license.txt b/license.txt index f1ad7ae..68a6f66 100644 --- a/license.txt +++ b/license.txt @@ -16,4 +16,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file +THE SOFTWARE. From b869aab8e11de319af2bd76181dd126d6d4e6711 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 3 Mar 2010 05:30:06 +0000 Subject: [PATCH 220/295] Updated to remove most of the warnings in Visual Studio. (There's still the one about all control paths returning a value left.) Fixed one warning (when an istream converts to void * to then convert to bool), and disabled three. --- CMakeLists.txt | 5 +++++ include/conversion.h | 3 ++- include/node.h | 2 +- include/nodereadimpl.h | 3 ++- include/parser.h | 2 +- parse.vcproj | 2 ++ test.vcproj | 2 ++ yamlcpp.vcproj | 2 ++ 8 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f21473..60119d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,6 +13,11 @@ if(CMAKE_COMPILER_IS_GNUCC) set(CMAKE_CXX_FLAGS "-O2 -Wall -Wextra -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}") endif(CMAKE_COMPILER_IS_GNUCC) +if(MSVC) + set(LIB_TYPE) # I can't figure out how CMake handles Windows shared libraries + set(CMAKE_CXX_FLAGS "/W3 /wd4127 /wd4355 /D_SCL_SECURE_NO_WARNINGS ${CMAKE_CXX_FLAGS}") +endif(MSVC) + set(YAML_CPP_VERSION_MAJOR "0") set(YAML_CPP_VERSION_MINOR "2") set(YAML_CPP_VERSION_PATCH "4") diff --git a/include/conversion.h b/include/conversion.h index 13add1c..3a03053 100644 --- a/include/conversion.h +++ b/include/conversion.h @@ -23,7 +23,8 @@ namespace YAML inline bool Convert(const std::string& input, T& output, typename enable_if >::type * = 0) { std::stringstream stream(input); stream.unsetf(std::ios::dec); - return stream >> output; + stream >> output; + return !!stream; } } diff --git a/include/node.h b/include/node.h index 097ccd8..b059748 100644 --- a/include/node.h +++ b/include/node.h @@ -20,7 +20,7 @@ namespace YAML class Content; class Scanner; class Emitter; - class ParserState; + struct ParserState; enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP }; diff --git a/include/nodereadimpl.h b/include/nodereadimpl.h index 9ec024a..d315660 100644 --- a/include/nodereadimpl.h +++ b/include/nodereadimpl.h @@ -52,9 +52,10 @@ namespace YAML int operator,(flag, flag); template - void operator,(flag, T const&); + char operator,(flag, T const&); char operator,(int, flag); + int operator,(char, flag); } template diff --git a/include/parser.h b/include/parser.h index cd61c1c..fec63ea 100644 --- a/include/parser.h +++ b/include/parser.h @@ -15,7 +15,7 @@ namespace YAML { class Scanner; - class ParserState; + struct ParserState; struct Token; class Parser: private noncopyable diff --git a/parse.vcproj b/parse.vcproj index 1663a6f..23ef07c 100644 --- a/parse.vcproj +++ b/parse.vcproj @@ -39,6 +39,7 @@ /> Date: Wed, 3 Mar 2010 05:33:07 +0000 Subject: [PATCH 221/295] Disabled those warnings in the release version of the .svn too. --- parse.vcproj | 2 ++ test.vcproj | 2 ++ yamlcpp.vcproj | 2 ++ 3 files changed, 6 insertions(+) diff --git a/parse.vcproj b/parse.vcproj index 23ef07c..3bca65d 100644 --- a/parse.vcproj +++ b/parse.vcproj @@ -112,6 +112,7 @@ /> Date: Mon, 15 Mar 2010 04:10:36 +0000 Subject: [PATCH 222/295] Set alias nodes to return the tag of their anchor --- include/node.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/node.h b/include/node.h index b059748..d3cf791 100644 --- a/include/node.h +++ b/include/node.h @@ -77,7 +77,7 @@ namespace YAML bool IsReferenced() const { return m_referenced; } // for tags - const std::string GetTag() const { return m_tag; } // TODO: should an aliased node return its alias's tag? + const std::string GetTag() const { return IsAlias() ? m_pIdentity->GetTag() : m_tag; } // emitting friend Emitter& operator << (Emitter& out, const Node& node); From 11903da3fbab8c3fe3cb6964881a132a7ceb473c Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 15 Mar 2010 04:25:17 +0000 Subject: [PATCH 223/295] Added overloads for parsing stl maps and vectors --- include/stlnode.h | 36 ++++++++++++++++++++++++++++++++++++ include/yaml.h | 1 + test/spectests.cpp | 6 +++--- 3 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 include/stlnode.h diff --git a/include/stlnode.h b/include/stlnode.h new file mode 100644 index 0000000..cfe2f03 --- /dev/null +++ b/include/stlnode.h @@ -0,0 +1,36 @@ +#pragma once + +#ifndef STLNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define STLNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + +#include +#include + +namespace YAML +{ + template + void operator >> (const Node& node, std::vector& v) + { + v.clear(); + v.resize(node.size()); + for(unsigned i=0;i> v[i]; + } + + + template + void operator >> (const Node& node, std::map& m) + { + m.clear(); + for(Iterator it=node.begin();it!=node.end();++it) { + K k; + V v; + it.first() >> k; + it.second() >> v; + m[k] = v; + } + } +} + +#endif // STLNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml.h b/include/yaml.h index 6950ad7..d1e83ca 100644 --- a/include/yaml.h +++ b/include/yaml.h @@ -6,6 +6,7 @@ #include "parser.h" #include "node.h" +#include "stlnode.h" #include "iterator.h" #include "emitter.h" #include "stlemitter.h" diff --git a/test/spectests.cpp b/test/spectests.cpp index 3cfc25c..9648d9e 100644 --- a/test/spectests.cpp +++ b/test/spectests.cpp @@ -1121,9 +1121,9 @@ namespace Test { " 0.278"; PARSE(doc, input); - StringMap key; - key._["first"] = "Sammy"; - key._["last"] = "Sosa"; + std::map key; + key["first"] = "Sammy"; + key["last"] = "Sosa"; YAML_ASSERT(doc.size() == 1); YAML_ASSERT(doc[key].size() == 2); YAML_ASSERT(doc[key]["hr"] == 65); From d99cb95d2dfc518ebee06a34af8438bf75d17c31 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 15 Mar 2010 19:25:02 +0000 Subject: [PATCH 224/295] Tagged version 0.2.5 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 60119d4..984748d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ endif(MSVC) set(YAML_CPP_VERSION_MAJOR "0") set(YAML_CPP_VERSION_MINOR "2") -set(YAML_CPP_VERSION_PATCH "4") +set(YAML_CPP_VERSION_PATCH "5") set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}") enable_testing() From 78db8b02c8f52dee5e019acde8fb5c8fa1e12a87 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sat, 1 May 2010 20:05:15 +0000 Subject: [PATCH 225/295] Fixed missing header --- src/token.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/token.h b/src/token.h index cf7c0fe..bf4f922 100644 --- a/src/token.h +++ b/src/token.h @@ -5,7 +5,7 @@ #include "mark.h" -#include +#include #include #include From 12d2beda297af91cc3aa4cf592aa9a8d752c1a5a Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 18 Oct 2010 06:45:03 +0000 Subject: [PATCH 226/295] Merged r366:387 from the jbeder-event-api branch --- include/aliasmanager.h | 38 +++ include/anchor.h | 14 + include/emitfromevents.h | 43 +++ include/eventhandler.h | 34 +++ include/node.h | 29 +- include/nodeproperties.h | 14 + include/parser.h | 17 +- src/aliascontent.cpp | 22 +- src/aliascontent.h | 6 +- src/aliasmanager.cpp | 45 +++ src/collectionstack.h | 33 +++ src/content.cpp | 21 ++ src/content.h | 27 +- src/{parserstate.cpp => directives.cpp} | 10 +- src/directives.h | 27 ++ src/emitfromevents.cpp | 106 +++++++ src/map.cpp | 165 +---------- src/map.h | 15 +- src/node.cpp | 237 ++++++--------- src/nodebuilder.cpp | 142 +++++++++ src/nodebuilder.h | 59 ++++ src/parser.cpp | 77 +++-- src/parserstate.h | 37 --- src/ptr_stack.h | 41 +++ src/scalar.cpp | 26 +- src/scalar.h | 7 +- src/scanner.cpp | 36 +-- src/scanner.h | 6 - src/sequence.cpp | 102 +------ src/sequence.h | 10 +- src/singledocparser.cpp | 369 ++++++++++++++++++++++++ src/singledocparser.h | 63 ++++ src/tag.cpp | 10 +- src/tag.h | 4 +- util/parse.cpp | 22 +- 35 files changed, 1280 insertions(+), 634 deletions(-) create mode 100644 include/aliasmanager.h create mode 100644 include/anchor.h create mode 100644 include/emitfromevents.h create mode 100644 include/eventhandler.h create mode 100644 include/nodeproperties.h create mode 100644 src/aliasmanager.cpp create mode 100644 src/collectionstack.h create mode 100644 src/content.cpp rename src/{parserstate.cpp => directives.cpp} (69%) create mode 100644 src/directives.h create mode 100644 src/emitfromevents.cpp create mode 100644 src/nodebuilder.cpp create mode 100644 src/nodebuilder.h delete mode 100644 src/parserstate.h create mode 100644 src/ptr_stack.h create mode 100644 src/singledocparser.cpp create mode 100644 src/singledocparser.h diff --git a/include/aliasmanager.h b/include/aliasmanager.h new file mode 100644 index 0000000..caa6648 --- /dev/null +++ b/include/aliasmanager.h @@ -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 + +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 NodeByNode; + NodeByNode m_newIdentityByOldIdentity; + + typedef std::map AnchorByIdentity; + AnchorByIdentity m_anchorByIdentity; + + anchor_t m_curAnchor; + }; +} + +#endif // ALIASMANAGER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/anchor.h b/include/anchor.h new file mode 100644 index 0000000..c7b283a --- /dev/null +++ b/include/anchor.h @@ -0,0 +1,14 @@ +#pragma once + +#ifndef ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#include + +namespace YAML +{ + typedef std::size_t anchor_t; + const anchor_t NullAnchor = 0; +} + +#endif // ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/emitfromevents.h b/include/emitfromevents.h new file mode 100644 index 0000000..6c9b241 --- /dev/null +++ b/include/emitfromevents.h @@ -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 + +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 m_stateStack; + }; +} + +#endif // EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/eventhandler.h b/include/eventhandler.h new file mode 100644 index 0000000..f76b946 --- /dev/null +++ b/include/eventhandler.h @@ -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 + +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 + diff --git a/include/node.h b/include/node.h index d3cf791..a3c95aa 100644 --- a/include/node.h +++ b/include/node.h @@ -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,9 +34,18 @@ namespace YAML void Clear(); std::auto_ptr 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 pNode); + void Insert(std::auto_ptr pKey, std::auto_ptr pValue); + + CONTENT_TYPE GetType() const { return m_type; } // file location of start of this node const Mark GetMark() const { return m_mark; } @@ -97,19 +108,11 @@ namespace YAML template 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_TYPE m_type; Content *m_pContent; bool m_alias; const Node *m_pIdentity; diff --git a/include/nodeproperties.h b/include/nodeproperties.h new file mode 100644 index 0000000..ae435d5 --- /dev/null +++ b/include/nodeproperties.h @@ -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 diff --git a/include/parser.h b/include/parser.h index fec63ea..c0fd57b 100644 --- a/include/parser.h +++ b/include/parser.h @@ -4,19 +4,18 @@ #define PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "node.h" #include "noncopyable.h" #include -#include -#include -#include #include namespace YAML { - class Scanner; - struct ParserState; + struct Directives; + struct Mark; struct Token; + class EventHandler; + class Node; + class Scanner; class Parser: private noncopyable { @@ -28,6 +27,8 @@ namespace YAML operator bool() const; void Load(std::istream& in); + bool HandleNextDocument(EventHandler& eventHandler); + bool GetNextDocument(Node& document); void PrintTokens(std::ostream& out); @@ -36,10 +37,10 @@ namespace YAML void HandleDirective(const Token& token); void HandleYamlDirective(const Token& token); void HandleTagDirective(const Token& token); - + private: std::auto_ptr m_pScanner; - std::auto_ptr m_pState; + std::auto_ptr m_pDirectives; }; } diff --git a/src/aliascontent.cpp b/src/aliascontent.cpp index 111938b..e59d5ad 100644 --- a/src/aliascontent.cpp +++ b/src/aliascontent.cpp @@ -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 ::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); diff --git a/src/aliascontent.h b/src/aliascontent.h index a69c28b..d5893b4 100644 --- a/src/aliascontent.h +++ b/src/aliascontent.h @@ -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 ::const_iterator&) const; virtual bool GetBegin(std::map ::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 *); diff --git a/src/aliasmanager.cpp b/src/aliasmanager.cpp new file mode 100644 index 0000000..61443a9 --- /dev/null +++ b/src/aliasmanager.cpp @@ -0,0 +1,45 @@ +#include "aliasmanager.h" +#include "node.h" +#include +#include + +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; + } +} diff --git a/src/collectionstack.h b/src/collectionstack.h new file mode 100644 index 0000000..fd3b885 --- /dev/null +++ b/src/collectionstack.h @@ -0,0 +1,33 @@ +#pragma once + +#ifndef COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + +#include +#include + +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 collectionStack; + }; +} + +#endif // COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/content.cpp b/src/content.cpp new file mode 100644 index 0000000..208e988 --- /dev/null +++ b/src/content.cpp @@ -0,0 +1,21 @@ +#include "content.h" +#include "node.h" +#include + +namespace YAML +{ + void Content::SetData(const std::string&) + { + assert(false); // TODO: throw + } + + void Content::Append(std::auto_ptr) + { + assert(false); // TODO: throw + } + + void Content::Insert(std::auto_ptr, std::auto_ptr) + { + assert(false); // TODO: throw + } +} diff --git a/src/content.h b/src/content.h index d6e0e8c..2c8cc8a 100644 --- a/src/content.h +++ b/src/content.h @@ -4,32 +4,30 @@ #define CONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include -#include -#include "parserstate.h" +#include "anchor.h" #include "exceptions.h" #include "ltnode.h" +#include +#include +#include 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 ::const_iterator&) const { return false; } virtual bool GetBegin(std::map ::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 pNode); + virtual void Insert(std::auto_ptr pKey, std::auto_ptr 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; } diff --git a/src/parserstate.cpp b/src/directives.cpp similarity index 69% rename from src/parserstate.cpp rename to src/directives.cpp index ebd6609..faf1483 100644 --- a/src/parserstate.cpp +++ b/src/directives.cpp @@ -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 ::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; } } diff --git a/src/directives.h b/src/directives.h new file mode 100644 index 0000000..e063faa --- /dev/null +++ b/src/directives.h @@ -0,0 +1,27 @@ +#pragma once + +#ifndef DIRECTIVES_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define DIRECTIVES_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + + +#include +#include + +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 tags; + }; +} + +#endif // DIRECTIVES_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/emitfromevents.cpp b/src/emitfromevents.cpp new file mode 100644 index 0000000..7cbf42c --- /dev/null +++ b/src/emitfromevents.cpp @@ -0,0 +1,106 @@ +#include "emitfromevents.h" +#include "emitter.h" +#include "null.h" +#include +#include + +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)); + } +} diff --git a/src/map.cpp b/src/map.cpp index 2db38b9..d9e799c 100644 --- a/src/map.cpp +++ b/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 pKey = it->first->Clone(); - std::auto_ptr 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 ::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 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 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 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 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 pKey, std::auto_ptr pValue) + void Map::Insert(std::auto_ptr pKey, std::auto_ptr 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) diff --git a/src/map.h b/src/map.h index 6887880..8eb44ee 100644 --- a/src/map.h +++ b/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 ::const_iterator& it) const; virtual bool GetEnd(std::map ::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 pKey, std::auto_ptr 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 pKey, std::auto_ptr pValue); - private: node_map m_data; }; diff --git a/src/node.cpp b/src/node.cpp index 24d3635..a292bf7 100644 --- a/src/node.cpp +++ b/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 #include 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_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() { Clear(); @@ -39,156 +37,112 @@ namespace YAML void Node::Clear() { delete m_pContent; + m_type = CT_NONE; m_pContent = 0; m_alias = false; m_referenced = false; - m_anchor.clear(); m_tag.clear(); } std::auto_ptr 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 (new Node(m_mark, m_anchor, m_tag, m_pContent)); + std::auto_ptr 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_type = type; + 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; + Clear(); + m_tag = tag; + m_alias = false; + m_pIdentity = this; + m_referenced = false; + } - 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; - } + void Node::InitAlias(const Mark& mark, const Node& identity) + { + Clear(); + m_mark = mark; + m_alias = true; + m_pIdentity = &identity; + if(identity.m_pContent) { + m_pContent = new AliasContent(identity.m_pContent); + m_type = identity.GetType(); } + identity.m_referenced = true; } - void Node::ParseTag(Scanner *pScanner, ParserState& state) + void Node::SetData(const std::string& data) { - Token& token = pScanner->peek(); - if(m_tag != "") - throw ParserException(token.mark, ErrorMsg::MULTIPLE_TAGS); + assert(m_pContent); // TODO: throw + m_pContent->SetData(data); + } - Tag tag(token); - m_tag = tag.Translate(state); - pScanner->pop(); + void Node::Append(std::auto_ptr pNode) + { + assert(m_pContent); // TODO: throw + m_pContent->Append(pNode); } - void Node::ParseAnchor(Scanner *pScanner, ParserState& /*state*/) + void Node::Insert(std::auto_ptr pKey, std::auto_ptr 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(); - } - - CONTENT_TYPE Node::GetType() const - { - if(!m_pContent) - return CT_NONE; - - 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; + assert(m_pContent); // TODO: throw + m_pContent->Insert(pKey, pValue); } // begin @@ -261,23 +215,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; } diff --git a/src/nodebuilder.cpp b/src/nodebuilder.cpp new file mode 100644 index 0000000..7da7d16 --- /dev/null +++ b/src/nodebuilder.cpp @@ -0,0 +1,142 @@ +#include "nodebuilder.h" +#include "mark.h" +#include "node.h" +#include "nodeproperties.h" +#include + +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 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 pNode = m_stack.pop(); + Insert(pNode); + } + + void NodeBuilder::Insert(std::auto_ptr 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 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); + } + } +} diff --git a/src/nodebuilder.h b/src/nodebuilder.h new file mode 100644 index 0000000..004aaad --- /dev/null +++ b/src/nodebuilder.h @@ -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 +#include +#include + +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 pNode); + void RegisterAnchor(anchor_t anchor, const Node& node); + + private: + Node& m_root; + bool m_initializedRoot; + bool m_finished; + + ptr_stack m_stack; + ptr_stack m_pendingKeys; + std::stack m_didPushKey; + + typedef std::vector Anchors; + Anchors m_anchors; + }; +} + +#endif // NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + diff --git a/src/parser.cpp b/src/parser.cpp index e9fd0a1..4d4b706 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,8 +1,13 @@ #include "parser.h" -#include "scanner.h" -#include "token.h" +#include "directives.h" +#include "eventhandler.h" #include "exceptions.h" -#include "parserstate.h" +#include "node.h" +#include "nodebuilder.h" +#include "scanner.h" +#include "singledocparser.h" +#include "tag.h" +#include "token.h" #include #include @@ -29,7 +34,25 @@ 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; } // GetNextDocument @@ -37,34 +60,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 +81,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 +104,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 +130,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) diff --git a/src/parserstate.h b/src/parserstate.h deleted file mode 100644 index 0b849c3..0000000 --- a/src/parserstate.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#ifndef PARSERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#define PARSERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 - - -#include -#include -#include -#include - -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 tags; - std::stack collectionStack; - }; -} - -#endif // PARSERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/ptr_stack.h b/src/ptr_stack.h new file mode 100644 index 0000000..4a3b20b --- /dev/null +++ b/src/ptr_stack.h @@ -0,0 +1,41 @@ +#pragma once + +#ifndef PTR_STACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define PTR_STACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#include "noncopyable.h" +#include +#include + +template +class ptr_stack: private YAML::noncopyable +{ +public: + ptr_stack() {} + ~ptr_stack() { clear(); } + + void clear() { + for(unsigned i=0;i t) { + m_data.push_back(NULL); + m_data.back() = t.release(); + } + std::auto_ptr pop() { + std::auto_ptr t(m_data.back()); + m_data.pop_back(); + return t; + } + T& top() { return *m_data.back(); } + +private: + std::vector m_data; +}; + +#endif // PTR_STACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/scalar.cpp b/src/scalar.cpp index 415bace..9383891 100644 --- a/src/scalar.cpp +++ b/src/scalar.cpp @@ -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) diff --git a/src/scalar.h b/src/scalar.h index 1baecaa..5843470 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -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 { diff --git a/src/scanner.cpp b/src/scanner.cpp index 33052c2..2e5fef7 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -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 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(); - } } diff --git a/src/scanner.h b/src/scanner.h index 28ce96d..17908cc 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -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 m_indents; std::vector m_indentRefs; // for "garbage collection" std::stack m_flows; - std::map m_anchors; }; } diff --git a/src/sequence.cpp b/src/sequence.cpp index 0f96e27..60a0f14 100644 --- a/src/sequence.cpp +++ b/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 namespace YAML @@ -12,12 +10,6 @@ namespace YAML } - Sequence::Sequence(const std::vector& data) - { - for(std::size_t i=0;iClone().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 ::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 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;iEmitEvents(am, eventHandler); + eventHandler.OnSequenceEnd(); } int Sequence::Compare(Content *pContent) diff --git a/src/sequence.h b/src/sequence.h index 49bdc83..342c5cb 100644 --- a/src/sequence.h +++ b/src/sequence.h @@ -15,19 +15,17 @@ namespace YAML { public: Sequence(); - Sequence(const std::vector& data); virtual ~Sequence(); void Clear(); - virtual Content *Clone() const; virtual bool GetBegin(std::vector ::const_iterator& it) const; virtual bool GetEnd(std::vector ::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 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 m_data; }; diff --git a/src/singledocparser.cpp b/src/singledocparser.cpp new file mode 100644 index 0000000..964212e --- /dev/null +++ b/src/singledocparser.cpp @@ -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 +#include + +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; + } +} diff --git a/src/singledocparser.h b/src/singledocparser.h new file mode 100644 index 0000000..19e670e --- /dev/null +++ b/src/singledocparser.h @@ -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 +#include +#include + +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 m_pCollectionStack; + + typedef std::map Anchors; + Anchors m_anchors; + + anchor_t m_curAnchor; + }; +} + +#endif // SINGLEDOCPARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/tag.cpp b/src/tag.cpp index 694a4f3..30d68e1 100644 --- a/src/tag.cpp +++ b/src/tag.cpp @@ -1,6 +1,6 @@ #include "tag.h" +#include "directives.h" #include "token.h" -#include "parserstate.h" #include 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 "!"; diff --git a/src/tag.h b/src/tag.h index b448994..68aa296 100644 --- a/src/tag.h +++ b/src/tag.h @@ -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; diff --git a/util/parse.cpp b/util/parse.cpp index 8a92576..502e159 100644 --- a/util/parse.cpp +++ b/util/parse.cpp @@ -1,9 +1,25 @@ #include "yaml.h" #include #include +#include + +struct Params { + bool hasFile; + std::string fileName; +}; + +Params ParseArgs(int argc, char **argv) { + Params p; + + std::vector 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]); @@ -13,9 +29,9 @@ int main(int argc, char **argv) YAML::Parser parser(input); YAML::Node doc; while(parser.GetNextDocument(doc)) { - YAML::Emitter emitter; - emitter << doc; - std::cout << emitter.c_str() << "\n"; +// YAML::Emitter emitter; +// emitter << doc; +// std::cout << emitter.c_str() << "\n"; } } catch(const YAML::Exception& e) { std::cerr << e.what() << "\n"; From 2a256f2870f5849ebd9232f3521c28b89130ceb5 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 18 Oct 2010 07:05:53 +0000 Subject: [PATCH 227/295] Moved all the includes to a subfolder yaml-cpp so they don't interfere with other libraries' includes --- include/{ => yaml-cpp}/aliasmanager.h | 0 include/{ => yaml-cpp}/anchor.h | 0 include/{ => yaml-cpp}/conversion.h | 0 include/{ => yaml-cpp}/emitfromevents.h | 0 include/{ => yaml-cpp}/emitter.h | 0 include/{ => yaml-cpp}/emittermanip.h | 0 include/{ => yaml-cpp}/eventhandler.h | 0 include/{ => yaml-cpp}/exceptions.h | 0 include/{ => yaml-cpp}/iterator.h | 0 include/{ => yaml-cpp}/mark.h | 0 include/{ => yaml-cpp}/node.h | 0 include/{ => yaml-cpp}/nodeimpl.h | 0 include/{ => yaml-cpp}/nodeproperties.h | 0 include/{ => yaml-cpp}/nodereadimpl.h | 0 include/{ => yaml-cpp}/nodeutil.h | 0 include/{ => yaml-cpp}/noncopyable.h | 0 include/{ => yaml-cpp}/null.h | 0 include/{ => yaml-cpp}/ostream.h | 0 include/{ => yaml-cpp}/parser.h | 0 include/{ => yaml-cpp}/stlemitter.h | 0 include/{ => yaml-cpp}/stlnode.h | 0 include/{ => yaml-cpp}/traits.h | 0 include/{ => yaml-cpp}/yaml.h | 0 src/aliasmanager.cpp | 4 ++-- src/content.cpp | 2 +- src/content.h | 4 ++-- src/conversion.cpp | 2 +- src/emitfromevents.cpp | 6 +++--- src/emitter.cpp | 4 ++-- src/emitterstate.cpp | 2 +- src/emitterstate.h | 2 +- src/emitterutils.cpp | 2 +- src/emitterutils.h | 2 +- src/exp.cpp | 2 +- src/indentation.h | 2 +- src/iterator.cpp | 4 ++-- src/map.cpp | 6 +++--- src/node.cpp | 12 ++++++------ src/nodebuilder.cpp | 6 +++--- src/nodebuilder.h | 2 +- src/null.cpp | 4 ++-- src/ostream.cpp | 2 +- src/parser.cpp | 8 ++++---- src/ptr_stack.h | 2 +- src/scalar.cpp | 2 +- src/scanner.cpp | 2 +- src/scanscalar.cpp | 2 +- src/scantag.cpp | 2 +- src/scantoken.cpp | 2 +- src/sequence.cpp | 4 ++-- src/setting.h | 2 +- src/simplekey.cpp | 2 +- src/singledocparser.cpp | 4 ++-- src/singledocparser.h | 4 ++-- src/stream.h | 4 ++-- src/streamcharsource.h | 2 +- src/token.h | 2 +- test/emittertests.cpp | 2 +- test/parsertests.cpp | 2 +- test/spectests.cpp | 2 +- test/tests.cpp | 2 +- util/parse.cpp | 2 +- 62 files changed, 62 insertions(+), 62 deletions(-) rename include/{ => yaml-cpp}/aliasmanager.h (100%) rename include/{ => yaml-cpp}/anchor.h (100%) rename include/{ => yaml-cpp}/conversion.h (100%) rename include/{ => yaml-cpp}/emitfromevents.h (100%) rename include/{ => yaml-cpp}/emitter.h (100%) rename include/{ => yaml-cpp}/emittermanip.h (100%) rename include/{ => yaml-cpp}/eventhandler.h (100%) rename include/{ => yaml-cpp}/exceptions.h (100%) rename include/{ => yaml-cpp}/iterator.h (100%) rename include/{ => yaml-cpp}/mark.h (100%) rename include/{ => yaml-cpp}/node.h (100%) rename include/{ => yaml-cpp}/nodeimpl.h (100%) rename include/{ => yaml-cpp}/nodeproperties.h (100%) rename include/{ => yaml-cpp}/nodereadimpl.h (100%) rename include/{ => yaml-cpp}/nodeutil.h (100%) rename include/{ => yaml-cpp}/noncopyable.h (100%) rename include/{ => yaml-cpp}/null.h (100%) rename include/{ => yaml-cpp}/ostream.h (100%) rename include/{ => yaml-cpp}/parser.h (100%) rename include/{ => yaml-cpp}/stlemitter.h (100%) rename include/{ => yaml-cpp}/stlnode.h (100%) rename include/{ => yaml-cpp}/traits.h (100%) rename include/{ => yaml-cpp}/yaml.h (100%) diff --git a/include/aliasmanager.h b/include/yaml-cpp/aliasmanager.h similarity index 100% rename from include/aliasmanager.h rename to include/yaml-cpp/aliasmanager.h diff --git a/include/anchor.h b/include/yaml-cpp/anchor.h similarity index 100% rename from include/anchor.h rename to include/yaml-cpp/anchor.h diff --git a/include/conversion.h b/include/yaml-cpp/conversion.h similarity index 100% rename from include/conversion.h rename to include/yaml-cpp/conversion.h diff --git a/include/emitfromevents.h b/include/yaml-cpp/emitfromevents.h similarity index 100% rename from include/emitfromevents.h rename to include/yaml-cpp/emitfromevents.h diff --git a/include/emitter.h b/include/yaml-cpp/emitter.h similarity index 100% rename from include/emitter.h rename to include/yaml-cpp/emitter.h diff --git a/include/emittermanip.h b/include/yaml-cpp/emittermanip.h similarity index 100% rename from include/emittermanip.h rename to include/yaml-cpp/emittermanip.h diff --git a/include/eventhandler.h b/include/yaml-cpp/eventhandler.h similarity index 100% rename from include/eventhandler.h rename to include/yaml-cpp/eventhandler.h diff --git a/include/exceptions.h b/include/yaml-cpp/exceptions.h similarity index 100% rename from include/exceptions.h rename to include/yaml-cpp/exceptions.h diff --git a/include/iterator.h b/include/yaml-cpp/iterator.h similarity index 100% rename from include/iterator.h rename to include/yaml-cpp/iterator.h diff --git a/include/mark.h b/include/yaml-cpp/mark.h similarity index 100% rename from include/mark.h rename to include/yaml-cpp/mark.h diff --git a/include/node.h b/include/yaml-cpp/node.h similarity index 100% rename from include/node.h rename to include/yaml-cpp/node.h diff --git a/include/nodeimpl.h b/include/yaml-cpp/nodeimpl.h similarity index 100% rename from include/nodeimpl.h rename to include/yaml-cpp/nodeimpl.h diff --git a/include/nodeproperties.h b/include/yaml-cpp/nodeproperties.h similarity index 100% rename from include/nodeproperties.h rename to include/yaml-cpp/nodeproperties.h diff --git a/include/nodereadimpl.h b/include/yaml-cpp/nodereadimpl.h similarity index 100% rename from include/nodereadimpl.h rename to include/yaml-cpp/nodereadimpl.h diff --git a/include/nodeutil.h b/include/yaml-cpp/nodeutil.h similarity index 100% rename from include/nodeutil.h rename to include/yaml-cpp/nodeutil.h diff --git a/include/noncopyable.h b/include/yaml-cpp/noncopyable.h similarity index 100% rename from include/noncopyable.h rename to include/yaml-cpp/noncopyable.h diff --git a/include/null.h b/include/yaml-cpp/null.h similarity index 100% rename from include/null.h rename to include/yaml-cpp/null.h diff --git a/include/ostream.h b/include/yaml-cpp/ostream.h similarity index 100% rename from include/ostream.h rename to include/yaml-cpp/ostream.h diff --git a/include/parser.h b/include/yaml-cpp/parser.h similarity index 100% rename from include/parser.h rename to include/yaml-cpp/parser.h diff --git a/include/stlemitter.h b/include/yaml-cpp/stlemitter.h similarity index 100% rename from include/stlemitter.h rename to include/yaml-cpp/stlemitter.h diff --git a/include/stlnode.h b/include/yaml-cpp/stlnode.h similarity index 100% rename from include/stlnode.h rename to include/yaml-cpp/stlnode.h diff --git a/include/traits.h b/include/yaml-cpp/traits.h similarity index 100% rename from include/traits.h rename to include/yaml-cpp/traits.h diff --git a/include/yaml.h b/include/yaml-cpp/yaml.h similarity index 100% rename from include/yaml.h rename to include/yaml-cpp/yaml.h diff --git a/src/aliasmanager.cpp b/src/aliasmanager.cpp index 61443a9..89dfd03 100644 --- a/src/aliasmanager.cpp +++ b/src/aliasmanager.cpp @@ -1,5 +1,5 @@ -#include "aliasmanager.h" -#include "node.h" +#include "yaml-cpp/aliasmanager.h" +#include "yaml-cpp/node.h" #include #include diff --git a/src/content.cpp b/src/content.cpp index 208e988..a1540d1 100644 --- a/src/content.cpp +++ b/src/content.cpp @@ -1,5 +1,5 @@ #include "content.h" -#include "node.h" +#include "yaml-cpp/node.h" #include namespace YAML diff --git a/src/content.h b/src/content.h index 2c8cc8a..598b290 100644 --- a/src/content.h +++ b/src/content.h @@ -4,8 +4,8 @@ #define CONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "anchor.h" -#include "exceptions.h" +#include "yaml-cpp/anchor.h" +#include "yaml-cpp/exceptions.h" #include "ltnode.h" #include #include diff --git a/src/conversion.cpp b/src/conversion.cpp index 3b76ef2..f81e1a0 100644 --- a/src/conversion.cpp +++ b/src/conversion.cpp @@ -1,4 +1,4 @@ -#include "conversion.h" +#include "yaml-cpp/conversion.h" #include //////////////////////////////////////////////////////////////// diff --git a/src/emitfromevents.cpp b/src/emitfromevents.cpp index 7cbf42c..ce9c2ac 100644 --- a/src/emitfromevents.cpp +++ b/src/emitfromevents.cpp @@ -1,6 +1,6 @@ -#include "emitfromevents.h" -#include "emitter.h" -#include "null.h" +#include "yaml-cpp/emitfromevents.h" +#include "yaml-cpp/emitter.h" +#include "yaml-cpp/null.h" #include #include diff --git a/src/emitter.cpp b/src/emitter.cpp index 675fcf8..c036b8f 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -1,8 +1,8 @@ -#include "emitter.h" +#include "yaml-cpp/emitter.h" #include "emitterstate.h" #include "emitterutils.h" #include "indentation.h" -#include "exceptions.h" +#include "yaml-cpp/exceptions.h" #include namespace YAML diff --git a/src/emitterstate.cpp b/src/emitterstate.cpp index 2906679..1214ac5 100644 --- a/src/emitterstate.cpp +++ b/src/emitterstate.cpp @@ -1,5 +1,5 @@ #include "emitterstate.h" -#include "exceptions.h" +#include "yaml-cpp/exceptions.h" namespace YAML { diff --git a/src/emitterstate.h b/src/emitterstate.h index b5be269..87621b4 100644 --- a/src/emitterstate.h +++ b/src/emitterstate.h @@ -5,7 +5,7 @@ #include "setting.h" -#include "emittermanip.h" +#include "yaml-cpp/emittermanip.h" #include #include #include diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index 62a7ef3..c80b506 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -1,7 +1,7 @@ #include "emitterutils.h" #include "exp.h" #include "indentation.h" -#include "exceptions.h" +#include "yaml-cpp/exceptions.h" #include "stringsource.h" #include #include diff --git a/src/emitterutils.h b/src/emitterutils.h index 7ceb6ff..3438745 100644 --- a/src/emitterutils.h +++ b/src/emitterutils.h @@ -4,7 +4,7 @@ #define EMITTERUTILS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "ostream.h" +#include "yaml-cpp/ostream.h" #include namespace YAML diff --git a/src/exp.cpp b/src/exp.cpp index 8dd3479..a23f441 100644 --- a/src/exp.cpp +++ b/src/exp.cpp @@ -1,5 +1,5 @@ #include "exp.h" -#include "exceptions.h" +#include "yaml-cpp/exceptions.h" #include namespace YAML diff --git a/src/indentation.h b/src/indentation.h index 2e2c967..db382ef 100644 --- a/src/indentation.h +++ b/src/indentation.h @@ -4,7 +4,7 @@ #define INDENTATION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "ostream.h" +#include "yaml-cpp/ostream.h" #include namespace YAML diff --git a/src/iterator.cpp b/src/iterator.cpp index 5d3bc9b..2b7742b 100644 --- a/src/iterator.cpp +++ b/src/iterator.cpp @@ -1,5 +1,5 @@ -#include "node.h" -#include "exceptions.h" +#include "yaml-cpp/node.h" +#include "yaml-cpp/exceptions.h" #include "iterpriv.h" namespace YAML diff --git a/src/map.cpp b/src/map.cpp index d9e799c..902b256 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -1,7 +1,7 @@ #include "map.h" -#include "node.h" -#include "eventhandler.h" -#include "exceptions.h" +#include "yaml-cpp/node.h" +#include "yaml-cpp/eventhandler.h" +#include "yaml-cpp/exceptions.h" namespace YAML { diff --git a/src/node.cpp b/src/node.cpp index a292bf7..7828ce5 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -1,14 +1,14 @@ -#include "node.h" +#include "yaml-cpp/node.h" #include "aliascontent.h" -#include "aliasmanager.h" +#include "yaml-cpp/aliasmanager.h" #include "content.h" -#include "emitfromevents.h" -#include "emitter.h" -#include "eventhandler.h" +#include "yaml-cpp/emitfromevents.h" +#include "yaml-cpp/emitter.h" +#include "yaml-cpp/eventhandler.h" #include "iterpriv.h" #include "map.h" #include "nodebuilder.h" -#include "nodeproperties.h" +#include "yaml-cpp/nodeproperties.h" #include "scalar.h" #include "scanner.h" #include "sequence.h" diff --git a/src/nodebuilder.cpp b/src/nodebuilder.cpp index 7da7d16..447ff87 100644 --- a/src/nodebuilder.cpp +++ b/src/nodebuilder.cpp @@ -1,7 +1,7 @@ #include "nodebuilder.h" -#include "mark.h" -#include "node.h" -#include "nodeproperties.h" +#include "yaml-cpp/mark.h" +#include "yaml-cpp/node.h" +#include "yaml-cpp/nodeproperties.h" #include namespace YAML diff --git a/src/nodebuilder.h b/src/nodebuilder.h index 004aaad..9ef6815 100644 --- a/src/nodebuilder.h +++ b/src/nodebuilder.h @@ -3,7 +3,7 @@ #ifndef NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "eventhandler.h" +#include "yaml-cpp/eventhandler.h" #include "ptr_stack.h" #include #include diff --git a/src/null.cpp b/src/null.cpp index faa05fb..08fa9aa 100644 --- a/src/null.cpp +++ b/src/null.cpp @@ -1,5 +1,5 @@ -#include "null.h" -#include "node.h" +#include "yaml-cpp/null.h" +#include "yaml-cpp/node.h" namespace YAML { diff --git a/src/ostream.cpp b/src/ostream.cpp index 463a450..a7f1e14 100644 --- a/src/ostream.cpp +++ b/src/ostream.cpp @@ -1,4 +1,4 @@ -#include "ostream.h" +#include "yaml-cpp/ostream.h" #include namespace YAML diff --git a/src/parser.cpp b/src/parser.cpp index 4d4b706..01afbd7 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,8 +1,8 @@ -#include "parser.h" +#include "yaml-cpp/parser.h" #include "directives.h" -#include "eventhandler.h" -#include "exceptions.h" -#include "node.h" +#include "yaml-cpp/eventhandler.h" +#include "yaml-cpp/exceptions.h" +#include "yaml-cpp/node.h" #include "nodebuilder.h" #include "scanner.h" #include "singledocparser.h" diff --git a/src/ptr_stack.h b/src/ptr_stack.h index 4a3b20b..cac785b 100644 --- a/src/ptr_stack.h +++ b/src/ptr_stack.h @@ -3,7 +3,7 @@ #ifndef PTR_STACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define PTR_STACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "noncopyable.h" +#include "yaml-cpp/noncopyable.h" #include #include diff --git a/src/scalar.cpp b/src/scalar.cpp index 9383891..8bba6f7 100644 --- a/src/scalar.cpp +++ b/src/scalar.cpp @@ -1,5 +1,5 @@ #include "scalar.h" -#include "eventhandler.h" +#include "yaml-cpp/eventhandler.h" namespace YAML { diff --git a/src/scanner.cpp b/src/scanner.cpp index 2e5fef7..eb211f7 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -1,6 +1,6 @@ #include "scanner.h" #include "token.h" -#include "exceptions.h" +#include "yaml-cpp/exceptions.h" #include "exp.h" #include #include diff --git a/src/scanscalar.cpp b/src/scanscalar.cpp index 50b8bf7..1adc469 100644 --- a/src/scanscalar.cpp +++ b/src/scanscalar.cpp @@ -1,7 +1,7 @@ #include "scanscalar.h" #include "scanner.h" #include "exp.h" -#include "exceptions.h" +#include "yaml-cpp/exceptions.h" #include "token.h" namespace YAML diff --git a/src/scantag.cpp b/src/scantag.cpp index f08218e..b71cbcc 100644 --- a/src/scantag.cpp +++ b/src/scantag.cpp @@ -1,7 +1,7 @@ #include "scanner.h" #include "regex.h" #include "exp.h" -#include "exceptions.h" +#include "yaml-cpp/exceptions.h" namespace YAML { diff --git a/src/scantoken.cpp b/src/scantoken.cpp index 3e7e1cc..768ed7f 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -1,6 +1,6 @@ #include "scanner.h" #include "token.h" -#include "exceptions.h" +#include "yaml-cpp/exceptions.h" #include "exp.h" #include "scanscalar.h" #include "scantag.h" diff --git a/src/sequence.cpp b/src/sequence.cpp index 60a0f14..41e3710 100644 --- a/src/sequence.cpp +++ b/src/sequence.cpp @@ -1,6 +1,6 @@ #include "sequence.h" -#include "eventhandler.h" -#include "node.h" +#include "yaml-cpp/eventhandler.h" +#include "yaml-cpp/node.h" #include namespace YAML diff --git a/src/setting.h b/src/setting.h index 5619c59..f11142b 100644 --- a/src/setting.h +++ b/src/setting.h @@ -6,7 +6,7 @@ #include #include -#include "noncopyable.h" +#include "yaml-cpp/noncopyable.h" namespace YAML { diff --git a/src/simplekey.cpp b/src/simplekey.cpp index d8d1932..857a9e0 100644 --- a/src/simplekey.cpp +++ b/src/simplekey.cpp @@ -1,6 +1,6 @@ #include "scanner.h" #include "token.h" -#include "exceptions.h" +#include "yaml-cpp/exceptions.h" #include "exp.h" namespace YAML diff --git a/src/singledocparser.cpp b/src/singledocparser.cpp index 964212e..85844a3 100644 --- a/src/singledocparser.cpp +++ b/src/singledocparser.cpp @@ -1,8 +1,8 @@ #include "singledocparser.h" #include "collectionstack.h" #include "directives.h" -#include "eventhandler.h" -#include "exceptions.h" +#include "yaml-cpp/eventhandler.h" +#include "yaml-cpp/exceptions.h" #include "scanner.h" #include "tag.h" #include "token.h" diff --git a/src/singledocparser.h b/src/singledocparser.h index 19e670e..28355b8 100644 --- a/src/singledocparser.h +++ b/src/singledocparser.h @@ -4,8 +4,8 @@ #define SINGLEDOCPARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "anchor.h" -#include "noncopyable.h" +#include "yaml-cpp/anchor.h" +#include "yaml-cpp/noncopyable.h" #include #include #include diff --git a/src/stream.h b/src/stream.h index 5d78551..952f6bf 100644 --- a/src/stream.h +++ b/src/stream.h @@ -4,8 +4,8 @@ #define STREAM_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "noncopyable.h" -#include "mark.h" +#include "yaml-cpp/noncopyable.h" +#include "yaml-cpp/mark.h" #include #include #include diff --git a/src/streamcharsource.h b/src/streamcharsource.h index 10debc8..12548a4 100644 --- a/src/streamcharsource.h +++ b/src/streamcharsource.h @@ -4,7 +4,7 @@ #define STREAMCHARSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "noncopyable.h" +#include "yaml-cpp/noncopyable.h" #include namespace YAML diff --git a/src/token.h b/src/token.h index bf4f922..ba2eb59 100644 --- a/src/token.h +++ b/src/token.h @@ -4,7 +4,7 @@ #define TOKEN_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "mark.h" +#include "yaml-cpp/mark.h" #include #include #include diff --git a/test/emittertests.cpp b/test/emittertests.cpp index 58c3d92..b379e55 100644 --- a/test/emittertests.cpp +++ b/test/emittertests.cpp @@ -1,5 +1,5 @@ #include "tests.h" -#include "yaml.h" +#include "yaml-cpp/yaml.h" namespace Test { diff --git a/test/parsertests.cpp b/test/parsertests.cpp index 47b1d8b..7137aa7 100644 --- a/test/parsertests.cpp +++ b/test/parsertests.cpp @@ -1,5 +1,5 @@ #include "tests.h" -#include "yaml.h" +#include "yaml-cpp/yaml.h" #include #include diff --git a/test/spectests.cpp b/test/spectests.cpp index 9648d9e..d809b69 100644 --- a/test/spectests.cpp +++ b/test/spectests.cpp @@ -1,5 +1,5 @@ #include "spectests.h" -#include "yaml.h" +#include "yaml-cpp/yaml.h" #include #include #include diff --git a/test/tests.cpp b/test/tests.cpp index 492a5d1..b2c2d13 100644 --- a/test/tests.cpp +++ b/test/tests.cpp @@ -2,7 +2,7 @@ #include "emittertests.h" #include "parsertests.h" #include "spectests.h" -#include "yaml.h" +#include "yaml-cpp/yaml.h" #include #include #include diff --git a/util/parse.cpp b/util/parse.cpp index 502e159..be8a58b 100644 --- a/util/parse.cpp +++ b/util/parse.cpp @@ -1,4 +1,4 @@ -#include "yaml.h" +#include "yaml-cpp/yaml.h" #include #include #include From 7e511c41ad3767ab16eb000232666489fc48b225 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 18 Oct 2010 07:09:07 +0000 Subject: [PATCH 228/295] Forgot to add the new header location to the project (not important for compiling, but it is for the various generators) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 984748d..8635ba9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,7 +43,7 @@ set(_INSTALL_DESTINATIONS ARCHIVE DESTINATION lib${LIB_SUFFIX} ) # -file(GLOB public_headers include/[a-z]*.h) +file(GLOB public_headers include/yaml-cpp/[a-z]*.h) file(GLOB private_headers src/[a-z]*.h) file(GLOB sources src/[a-z]*.cpp) From 91944e45381e59eabc501a7a329f43cd25f21213 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 18 Oct 2010 07:22:53 +0000 Subject: [PATCH 229/295] Fixed the rest of the includes to explicitly state yaml-cpp/ --- include/yaml-cpp/aliasmanager.h | 2 +- include/yaml-cpp/conversion.h | 4 ++-- include/yaml-cpp/emitfromevents.h | 2 +- include/yaml-cpp/emitter.h | 6 +++--- include/yaml-cpp/eventhandler.h | 2 +- include/yaml-cpp/exceptions.h | 4 ++-- include/yaml-cpp/node.h | 14 +++++++------- include/yaml-cpp/nodeimpl.h | 2 +- include/yaml-cpp/parser.h | 2 +- include/yaml-cpp/yaml.h | 14 +++++++------- 10 files changed, 26 insertions(+), 26 deletions(-) diff --git a/include/yaml-cpp/aliasmanager.h b/include/yaml-cpp/aliasmanager.h index caa6648..4db9c89 100644 --- a/include/yaml-cpp/aliasmanager.h +++ b/include/yaml-cpp/aliasmanager.h @@ -3,7 +3,7 @@ #ifndef ALIASMANAGER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define ALIASMANAGER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "anchor.h" +#include "yaml-cpp/anchor.h" #include namespace YAML diff --git a/include/yaml-cpp/conversion.h b/include/yaml-cpp/conversion.h index 3a03053..fb2df7f 100644 --- a/include/yaml-cpp/conversion.h +++ b/include/yaml-cpp/conversion.h @@ -4,8 +4,8 @@ #define CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "null.h" -#include "traits.h" +#include "yaml-cpp/null.h" +#include "yaml-cpp/traits.h" #include #include diff --git a/include/yaml-cpp/emitfromevents.h b/include/yaml-cpp/emitfromevents.h index 6c9b241..a50e590 100644 --- a/include/yaml-cpp/emitfromevents.h +++ b/include/yaml-cpp/emitfromevents.h @@ -3,7 +3,7 @@ #ifndef EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "eventhandler.h" +#include "yaml-cpp/eventhandler.h" #include namespace YAML diff --git a/include/yaml-cpp/emitter.h b/include/yaml-cpp/emitter.h index a353e71..a7ae2b3 100644 --- a/include/yaml-cpp/emitter.h +++ b/include/yaml-cpp/emitter.h @@ -4,9 +4,9 @@ #define EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "emittermanip.h" -#include "ostream.h" -#include "null.h" +#include "yaml-cpp/emittermanip.h" +#include "yaml-cpp/ostream.h" +#include "yaml-cpp/null.h" #include #include #include diff --git a/include/yaml-cpp/eventhandler.h b/include/yaml-cpp/eventhandler.h index f76b946..f1f17db 100644 --- a/include/yaml-cpp/eventhandler.h +++ b/include/yaml-cpp/eventhandler.h @@ -3,7 +3,7 @@ #ifndef EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "anchor.h" +#include "yaml-cpp/anchor.h" #include namespace YAML diff --git a/include/yaml-cpp/exceptions.h b/include/yaml-cpp/exceptions.h index f81db59..7061626 100644 --- a/include/yaml-cpp/exceptions.h +++ b/include/yaml-cpp/exceptions.h @@ -4,8 +4,8 @@ #define EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "mark.h" -#include "traits.h" +#include "yaml-cpp/mark.h" +#include "yaml-cpp/traits.h" #include #include #include diff --git a/include/yaml-cpp/node.h b/include/yaml-cpp/node.h index a3c95aa..6938504 100644 --- a/include/yaml-cpp/node.h +++ b/include/yaml-cpp/node.h @@ -4,11 +4,11 @@ #define NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "conversion.h" -#include "exceptions.h" -#include "iterator.h" -#include "mark.h" -#include "noncopyable.h" +#include "yaml-cpp/conversion.h" +#include "yaml-cpp/exceptions.h" +#include "yaml-cpp/iterator.h" +#include "yaml-cpp/mark.h" +#include "yaml-cpp/noncopyable.h" #include #include #include @@ -138,7 +138,7 @@ namespace YAML bool operator != (const Node& node, const char *value); } -#include "nodeimpl.h" -#include "nodereadimpl.h" +#include "yaml-cpp/nodeimpl.h" +#include "yaml-cpp/nodereadimpl.h" #endif // NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/nodeimpl.h b/include/yaml-cpp/nodeimpl.h index e6cffc3..e9755de 100644 --- a/include/yaml-cpp/nodeimpl.h +++ b/include/yaml-cpp/nodeimpl.h @@ -4,7 +4,7 @@ #define NODEIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "nodeutil.h" +#include "yaml-cpp/nodeutil.h" namespace YAML { diff --git a/include/yaml-cpp/parser.h b/include/yaml-cpp/parser.h index c0fd57b..eec0e99 100644 --- a/include/yaml-cpp/parser.h +++ b/include/yaml-cpp/parser.h @@ -4,7 +4,7 @@ #define PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "noncopyable.h" +#include "yaml-cpp/noncopyable.h" #include #include diff --git a/include/yaml-cpp/yaml.h b/include/yaml-cpp/yaml.h index d1e83ca..052d306 100644 --- a/include/yaml-cpp/yaml.h +++ b/include/yaml-cpp/yaml.h @@ -4,12 +4,12 @@ #define YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#include "parser.h" -#include "node.h" -#include "stlnode.h" -#include "iterator.h" -#include "emitter.h" -#include "stlemitter.h" -#include "exceptions.h" +#include "yaml-cpp/parser.h" +#include "yaml-cpp/node.h" +#include "yaml-cpp/stlnode.h" +#include "yaml-cpp/iterator.h" +#include "yaml-cpp/emitter.h" +#include "yaml-cpp/stlemitter.h" +#include "yaml-cpp/exceptions.h" #endif // YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66 From 2d3722db854c605d55028012a32802af7cd044a2 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 18 Oct 2010 07:24:42 +0000 Subject: [PATCH 230/295] Made emitter noncopyable, which should fix any auto_ptr warnings --- include/yaml-cpp/emitter.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/yaml-cpp/emitter.h b/include/yaml-cpp/emitter.h index a7ae2b3..305e8e6 100644 --- a/include/yaml-cpp/emitter.h +++ b/include/yaml-cpp/emitter.h @@ -6,6 +6,7 @@ #include "yaml-cpp/emittermanip.h" #include "yaml-cpp/ostream.h" +#include "yaml-cpp/noncopyable.h" #include "yaml-cpp/null.h" #include #include @@ -15,7 +16,7 @@ namespace YAML { class EmitterState; - class Emitter + class Emitter: private noncopyable { public: Emitter(); From 59d126f5b0e21b11d31e55b35914cb8e8716d372 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 18 Oct 2010 21:35:34 +0000 Subject: [PATCH 231/295] Updated CMake iPhone settings --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8635ba9..40154ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,8 @@ project (YAML_CPP) set(LIB_TYPE SHARED) if(IPHONE) - set(CMAKE_OSX_SYSROOT iphoneos2.2.1) + set(CMAKE_OSX_SYSROOT iphoneos4.0) + set(CMAKE_OSX_ARCHITECTURES $(ARCHS_STANDARD_32_BIT)) set(LIB_TYPE) endif(IPHONE) @@ -59,6 +60,10 @@ set_target_properties(yaml-cpp PROPERTIES SOVERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}" ) +if(IPHONE) +set_target_properties(yaml-cpp PROPERTIES XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "3.0") +endif(IPHONE) + install(TARGETS yaml-cpp ${_INSTALL_DESTINATIONS}) install( FILES ${public_headers} From 973ce78fe174dc0a09f606ca8e0da187ba9c83da Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 19 Oct 2010 06:46:55 +0000 Subject: [PATCH 232/295] Merged the other-tags branch into the trunk (this wasn't an rX:Y merge, since the branch wasn't branched directly from the head of the trunk) --- include/yaml-cpp/emitter.h | 2 ++ include/yaml-cpp/emittermanip.h | 19 +++++++++++++++---- src/emitter.cpp | 20 +++++++++++++++++--- src/emitterutils.cpp | 10 ++++++---- src/emitterutils.h | 2 +- src/scantoken.cpp | 13 +++++++++---- src/singledocparser.cpp | 14 +++++++++++--- src/token.h | 5 +++-- 8 files changed, 64 insertions(+), 21 deletions(-) diff --git a/include/yaml-cpp/emitter.h b/include/yaml-cpp/emitter.h index 305e8e6..12ade38 100644 --- a/include/yaml-cpp/emitter.h +++ b/include/yaml-cpp/emitter.h @@ -78,6 +78,8 @@ namespace YAML void EmitEndMap(); void EmitKey(); void EmitValue(); + void EmitKindTag(); + void EmitTag(bool verbatim, const _Tag& tag); private: ostream m_stream; diff --git a/include/yaml-cpp/emittermanip.h b/include/yaml-cpp/emittermanip.h index c88054f..bbf48c4 100644 --- a/include/yaml-cpp/emittermanip.h +++ b/include/yaml-cpp/emittermanip.h @@ -11,6 +11,7 @@ namespace YAML enum EMITTER_MANIP { // general manipulators Auto, + TagByKind, // output character set EmitNonAscii, @@ -82,14 +83,24 @@ namespace YAML } struct _Tag { - _Tag(const std::string& content_): content(content_), verbatim(true) {} + explicit _Tag(const std::string& content_) + : content(content_), verbatim(true) + { + } std::string content; bool verbatim; }; - inline _Tag VerbatimTag(const std::string& content) { - return _Tag(content); - } + typedef _Tag VerbatimTag; + + struct LocalTag : public _Tag + { + explicit LocalTag(const std::string& content_) + : _Tag(content_) + { + verbatim = false; + } + }; struct _Comment { _Comment(const std::string& content_): content(content_) {} diff --git a/src/emitter.cpp b/src/emitter.cpp index c036b8f..1e0d555 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -120,6 +120,9 @@ namespace YAML case Value: EmitValue(); break; + case TagByKind: + EmitKindTag(); + break; default: m_pState->SetLocalValue(value); break; @@ -651,15 +654,26 @@ namespace YAML if(!good()) return *this; + EmitTag(tag.verbatim, tag); + return *this; + } + + void Emitter::EmitTag(bool verbatim, const _Tag& tag) + { PreAtomicWrite(); EmitSeparationIfNecessary(); - if(!Utils::WriteTag(m_stream, tag.content)) { + if(!Utils::WriteTag(m_stream, tag.content, verbatim)) { m_pState->SetError(ErrorMsg::INVALID_TAG); - return *this; + return; } m_pState->RequireSeparation(); // Note: no PostAtomicWrite() because we need another value for this node - return *this; + } + + void Emitter::EmitKindTag() + { + _Tag tag(""); + EmitTag(false, tag); } Emitter& Emitter::Write(const _Comment& comment) diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index c80b506..45e9f69 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -294,12 +294,13 @@ namespace YAML return WriteAliasName(out, str); } - bool WriteTag(ostream& out, const std::string& str) + bool WriteTag(ostream& out, const std::string& str, bool verbatim) { - out << "!<"; + out << (verbatim ? "!<" : "!"); StringCharSource buffer(str.c_str(), str.size()); + const RegEx& reValid = verbatim ? Exp::URI() : Exp::Tag(); while(buffer) { - int n = Exp::URI().Match(buffer); + int n = reValid.Match(buffer); if(n <= 0) return false; @@ -308,7 +309,8 @@ namespace YAML ++buffer; } } - out << ">"; + if (verbatim) + out << ">"; return true; } } diff --git a/src/emitterutils.h b/src/emitterutils.h index 3438745..8e2356c 100644 --- a/src/emitterutils.h +++ b/src/emitterutils.h @@ -18,7 +18,7 @@ namespace YAML bool WriteComment(ostream& out, const std::string& str, int postCommentIndent); bool WriteAlias(ostream& out, const std::string& str); bool WriteAnchor(ostream& out, const std::string& str); - bool WriteTag(ostream& out, const std::string& str); + bool WriteTag(ostream& out, const std::string& str, bool verbatim); } } diff --git a/src/scantoken.cpp b/src/scantoken.cpp index 768ed7f..82ea733 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -276,7 +276,12 @@ namespace YAML } else { bool canBeHandle; token.value = ScanTagHandle(INPUT, canBeHandle); - token.data = (token.value.empty() ? Tag::SECONDARY_HANDLE : Tag::PRIMARY_HANDLE); + if(!canBeHandle && token.value.empty()) + token.data = Tag::NON_SPECIFIC; + else if(token.value.empty()) + token.data = Tag::SECONDARY_HANDLE; + else + token.data = Tag::PRIMARY_HANDLE; // is there a suffix? if(canBeHandle && INPUT.peek() == Keys::Tag) { @@ -321,7 +326,7 @@ namespace YAML //if(Exp::IllegalCharInScalar.Matches(INPUT)) // throw ParserException(INPUT.mark(), ErrorMsg::CHAR_IN_SCALAR); - Token token(Token::SCALAR, mark); + Token token(Token::PLAIN_SCALAR, mark); token.value = scalar; m_tokens.push(token); } @@ -360,7 +365,7 @@ namespace YAML m_simpleKeyAllowed = false; m_canBeJSONFlow = true; - Token token(Token::SCALAR, mark); + Token token(Token::NON_PLAIN_SCALAR, mark); token.value = scalar; m_tokens.push(token); } @@ -427,7 +432,7 @@ namespace YAML m_simpleKeyAllowed = true; m_canBeJSONFlow = false; - Token token(Token::SCALAR, mark); + Token token(Token::NON_PLAIN_SCALAR, mark); token.value = scalar; m_tokens.push(token); } diff --git a/src/singledocparser.cpp b/src/singledocparser.cpp index 85844a3..c67a0ff 100644 --- a/src/singledocparser.cpp +++ b/src/singledocparser.cpp @@ -8,6 +8,7 @@ #include "token.h" #include #include +#include namespace YAML { @@ -73,10 +74,17 @@ namespace YAML anchor_t anchor; ParseProperties(tag, anchor); + const Token& token = m_scanner.peek(); + + // add non-specific tags + if(tag.empty()) + tag = (token.type == Token::NON_PLAIN_SCALAR ? "!" : "?"); + // now split based on what kind of node we should be - switch(m_scanner.peek().type) { - case Token::SCALAR: - eventHandler.OnScalar(mark, tag, anchor, m_scanner.peek().value); + switch(token.type) { + case Token::PLAIN_SCALAR: + case Token::NON_PLAIN_SCALAR: + eventHandler.OnScalar(mark, tag, anchor, token.value); m_scanner.pop(); return; case Token::FLOW_SEQ_START: diff --git a/src/token.h b/src/token.h index ba2eb59..63093fc 100644 --- a/src/token.h +++ b/src/token.h @@ -57,9 +57,10 @@ namespace YAML ANCHOR, ALIAS, TAG, - SCALAR + PLAIN_SCALAR, + NON_PLAIN_SCALAR }; - + // data Token(TYPE type_, const Mark& mark_): status(VALID), type(type_), mark(mark_), data(0) {} From 7bad58ba4700508963e97a9ee69ac0d100f32999 Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 19 Oct 2010 06:51:54 +0000 Subject: [PATCH 233/295] Merged the extra tests from other-tags into the trunk (forgot last commit) --- test/emittertests.cpp | 28 ++++++++++ test/parsertests.cpp | 115 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 142 insertions(+), 1 deletion(-) diff --git a/test/emittertests.cpp b/test/emittertests.cpp index b379e55..5b57958 100644 --- a/test/emittertests.cpp +++ b/test/emittertests.cpp @@ -373,6 +373,31 @@ namespace Test desiredOutput = "---\n- !\n []\n- !\n {}"; } + void ByKindTagWithScalar(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << YAML::DoubleQuoted << "12"; + out << "12"; + out << YAML::TagByKind << "12"; + out << YAML::EndSeq; + + desiredOutput = "---\n- \"12\"\n- 12\n- ! 12"; + } + + void LocalTagWithScalar(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::LocalTag("foo") << "bar"; + + desiredOutput = "--- !foo bar"; + } + + void BadLocalTag(YAML::Emitter& out, std::string& desiredError) + { + out << YAML::LocalTag("e!far") << "bar"; + + desiredError = "invalid tag"; + } + void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput) { out << YAML::BeginMap; @@ -789,6 +814,8 @@ namespace Test RunEmitterTest(&Emitter::VerbatimTagWithEmptySeq, "verbatim tag with empty seq", passed, total); RunEmitterTest(&Emitter::VerbatimTagWithEmptyMap, "verbatim tag with empty map", passed, total); RunEmitterTest(&Emitter::VerbatimTagWithEmptySeqAndMap, "verbatim tag with empty seq and map", passed, total); + RunEmitterTest(&Emitter::ByKindTagWithScalar, "by-kind tag with scalar", passed, total); + RunEmitterTest(&Emitter::LocalTagWithScalar, "local tag with scalar", passed, total); RunEmitterTest(&Emitter::ComplexDoc, "complex doc", passed, total); RunEmitterTest(&Emitter::STLContainers, "STL containers", passed, total); RunEmitterTest(&Emitter::SimpleComment, "simple comment", passed, total); @@ -815,6 +842,7 @@ namespace Test RunEmitterErrorTest(&Emitter::MissingValue, "missing value", passed, total); RunEmitterErrorTest(&Emitter::UnexpectedKey, "unexpected key", passed, total); RunEmitterErrorTest(&Emitter::UnexpectedValue, "unexpected value", passed, total); + RunEmitterErrorTest(&Emitter::BadLocalTag, "bad local tag", passed, total); std::cout << "Emitter tests: " << passed << "/" << total << " passed\n"; return passed == total; diff --git a/test/parsertests.cpp b/test/parsertests.cpp index 7137aa7..f013234 100644 --- a/test/parsertests.cpp +++ b/test/parsertests.cpp @@ -706,6 +706,106 @@ namespace Test return false; return true; } + + void PrepareNodeForTagExam(YAML::Node& doc, const std::string& input) + { + std::stringstream stream(input); + YAML::Parser parser(stream); + parser.GetNextDocument(doc); + } + + struct TagMismatch: public std::exception { + TagMismatch(const std::string& actualTag, const std::string& expectedTag) { + std::stringstream output; + output << "Tag has value \"" << actualTag << "\" but \"" << expectedTag << "\" was expected"; + what_ = output.str(); + } + virtual ~TagMismatch() throw() {} + virtual const char *what() const throw() { return what_.c_str(); } + + private: + std::string what_; + }; + + bool ExpectedTagValue(YAML::Node& node, const char* tag) + { + if(node.GetTag() == tag) + return true; + + throw TagMismatch(node.GetTag(), tag); + } + + bool DefaultPlainScalarTag() + { + YAML::Node node; + PrepareNodeForTagExam(node, "--- 12"); + + return ExpectedTagValue(node, "?"); + } + + bool DefaultSingleQuotedScalarTag() + { + YAML::Node node; + PrepareNodeForTagExam(node, "--- '12'"); + + return ExpectedTagValue(node, "!"); + } + + bool ExplicitNonSpecificPlainScalarTag() + { + YAML::Node node; + PrepareNodeForTagExam(node, "--- ! 12"); + + return ExpectedTagValue(node, "!"); + } + + bool BasicLocalTag() + { + YAML::Node node; + PrepareNodeForTagExam(node, "--- !foo 12"); + + return ExpectedTagValue(node, "!foo"); + } + + bool VerbatimLocalTag() + { + YAML::Node node; + PrepareNodeForTagExam(node, "--- ! 12"); + + return ExpectedTagValue(node, "!foo"); + } + + bool StandardShortcutTag() + { + YAML::Node node; + PrepareNodeForTagExam(node, "--- !!int 12"); + + return ExpectedTagValue(node, "tag:yaml.org,2002:int"); + } + + bool VerbatimURITag() + { + YAML::Node node; + PrepareNodeForTagExam(node, "--- ! 12"); + + return ExpectedTagValue(node, "tag:yaml.org,2002:int"); + } + + bool DefaultSequenceTag() + { + YAML::Node node; + PrepareNodeForTagExam(node, "--- [12]"); + + return ExpectedTagValue(node, "?"); + } + + bool ExplicitNonSpecificSequenceTag() + { + YAML::Node node; + PrepareNodeForTagExam(node, "--- ! [12]"); + + return ExpectedTagValue(node, "!"); + } } namespace { @@ -746,7 +846,10 @@ namespace Test ok = test(); } catch(const YAML::Exception& e) { ok = false; - error = e.msg; + error = e.what(); + } catch(const Parser::TagMismatch& e) { + ok = false; + error = e.what(); } if(ok) { passed++; @@ -969,6 +1072,16 @@ namespace Test RunParserTest(&Parser::Bases, "bases", passed, total); RunParserTest(&Parser::KeyNotFound, "key not found", passed, total); RunParserTest(&Parser::DuplicateKey, "duplicate key", passed, total); + RunParserTest(&Parser::DefaultPlainScalarTag, "default plain scalar tag", passed, total); + RunParserTest(&Parser::DefaultSingleQuotedScalarTag, "default single-quoted scalar tag", passed, total); + RunParserTest(&Parser::ExplicitNonSpecificPlainScalarTag, "explicit, non-specific plain scalar tag", passed, total); + RunParserTest(&Parser::BasicLocalTag, "basic local tag", passed, total); + RunParserTest(&Parser::VerbatimLocalTag, "verbatim local tag", passed, total); + RunParserTest(&Parser::StandardShortcutTag, "standard shortcut tag", passed, total); + RunParserTest(&Parser::VerbatimURITag, "verbatim URI tag", passed, total); + RunParserTest(&Parser::DefaultPlainScalarTag, "default plain scalar tag", passed, total); + RunParserTest(&Parser::DefaultSequenceTag, "default sequence tag", passed, total); + RunParserTest(&Parser::ExplicitNonSpecificSequenceTag, "explicit, non-specific sequence tag", passed, total); RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed, total); RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed, total); From 59745a4cff715f48ee08b365e853b7ed3623b38f Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 21 Oct 2010 22:02:29 +0000 Subject: [PATCH 234/295] Added YAML::Newline manipulator for the emitter --- include/yaml-cpp/emitter.h | 1 + include/yaml-cpp/emittermanip.h | 1 + src/emitter.cpp | 16 ++++++++++++++-- test/emittertests.cpp | 27 ++++++++++++++++++++++++++- util/parse.cpp | 22 +++++++++++++++++++++- 5 files changed, 63 insertions(+), 4 deletions(-) diff --git a/include/yaml-cpp/emitter.h b/include/yaml-cpp/emitter.h index 12ade38..9e01f76 100644 --- a/include/yaml-cpp/emitter.h +++ b/include/yaml-cpp/emitter.h @@ -78,6 +78,7 @@ namespace YAML void EmitEndMap(); void EmitKey(); void EmitValue(); + void EmitNewline(); void EmitKindTag(); void EmitTag(bool verbatim, const _Tag& tag); diff --git a/include/yaml-cpp/emittermanip.h b/include/yaml-cpp/emittermanip.h index bbf48c4..a20bfb6 100644 --- a/include/yaml-cpp/emittermanip.h +++ b/include/yaml-cpp/emittermanip.h @@ -12,6 +12,7 @@ namespace YAML // general manipulators Auto, TagByKind, + Newline, // output character set EmitNonAscii, diff --git a/src/emitter.cpp b/src/emitter.cpp index 1e0d555..3d50d3f 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -123,6 +123,9 @@ namespace YAML case TagByKind: EmitKindTag(); break; + case Newline: + EmitNewline(); + break; default: m_pState->SetLocalValue(value); break; @@ -505,6 +508,15 @@ namespace YAML assert(false); } + // EmitNewline + void Emitter::EmitNewline() + { + if(!good()) + return; + + m_stream << '\n'; + } + // ******************************************************************************************* // overloads of Write @@ -551,7 +563,7 @@ namespace YAML PostAtomicWrite(); return *this; } - + void Emitter::PreWriteIntegralType(std::stringstream& str) { PreAtomicWrite(); @@ -572,7 +584,7 @@ namespace YAML assert(false); } } - + void Emitter::PostWriteIntegralType(const std::stringstream& str) { m_stream << str.str(); diff --git a/test/emittertests.cpp b/test/emittertests.cpp index 5b57958..057300c 100644 --- a/test/emittertests.cpp +++ b/test/emittertests.cpp @@ -651,7 +651,29 @@ namespace Test desiredOutput = "---\n-\n x: 5\n bar: hello\n- ~"; } - + + void NewlineAtEnd(YAML::Emitter& out, std::string& desiredOutput) + { + out << "Hello" << YAML::Newline << YAML::Newline; + desiredOutput = "--- Hello\n\n"; + } + + void NewlineInBlockSequence(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << "a" << YAML::Newline << "b" << "c" << YAML::Newline << "d"; + out << YAML::EndSeq; + desiredOutput = "---\n- a\n\n- b\n- c\n\n- d"; + } + + void NewlineInFlowSequence(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Flow << YAML::BeginSeq; + out << "a" << YAML::Newline << "b" << "c" << YAML::Newline << "d"; + out << YAML::EndSeq; + desiredOutput = "--- [a\n, b, c\n, d]"; + } + //////////////////////////////////////////////////////////////////////////////////////////////////////// // incorrect emitting @@ -832,6 +854,9 @@ namespace Test RunEmitterTest(&Emitter::UserTypeInContainer, "user type in container", passed, total); RunEmitterTest(&Emitter::PointerToInt, "pointer to int", passed, total); RunEmitterTest(&Emitter::PointerToUserType, "pointer to user type", passed, total); + RunEmitterTest(&Emitter::NewlineAtEnd, "newline at end", passed, total); + RunEmitterTest(&Emitter::NewlineInBlockSequence, "newline in block sequence", passed, total); + RunEmitterTest(&Emitter::NewlineInFlowSequence, "newline in flow sequence", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total); diff --git a/util/parse.cpp b/util/parse.cpp index be8a58b..35b9dd2 100644 --- a/util/parse.cpp +++ b/util/parse.cpp @@ -1,4 +1,5 @@ #include "yaml-cpp/yaml.h" +#include "yaml-cpp/eventhandler.h" #include #include #include @@ -16,6 +17,23 @@ Params ParseArgs(int argc, char **argv) { return p; } +class NullEventHandler: public YAML::EventHandler +{ +public: + virtual void OnDocumentStart(const YAML::Mark&) {} + virtual void OnDocumentEnd() {} + + virtual void OnNull(const std::string&, YAML::anchor_t) {} + virtual void OnAlias(const YAML::Mark&, YAML::anchor_t) {} + virtual void OnScalar(const YAML::Mark&, const std::string&, YAML::anchor_t, const std::string&) {} + + virtual void OnSequenceStart(const YAML::Mark&, const std::string&, YAML::anchor_t) {} + virtual void OnSequenceEnd() {} + + virtual void OnMapStart(const YAML::Mark&, const std::string&, YAML::anchor_t) {} + virtual void OnMapEnd() {} +}; + int main(int argc, char **argv) { Params p = ParseArgs(argc, argv); @@ -28,7 +46,9 @@ int main(int argc, char **argv) try { YAML::Parser parser(input); YAML::Node doc; - while(parser.GetNextDocument(doc)) { + NullEventHandler handler; +// while(parser.GetNextDocument(doc)) { + while(parser.HandleNextDocument(handler)) { // YAML::Emitter emitter; // emitter << doc; // std::cout << emitter.c_str() << "\n"; From cb8eee46f095b8cad7b737897cbff50eaaf5ea5c Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 22 Oct 2010 03:53:33 +0000 Subject: [PATCH 235/295] Added more tests for the newline, and disallowed newlines after implicit block keys --- include/yaml-cpp/emitter.h | 2 ++ src/emitfromevents.cpp | 2 +- src/emitter.cpp | 15 +++++++++++++-- test/emittertests.cpp | 38 ++++++++++++++++++++++++++++++++++++++ util/parse.cpp | 9 ++++----- 5 files changed, 58 insertions(+), 8 deletions(-) diff --git a/include/yaml-cpp/emitter.h b/include/yaml-cpp/emitter.h index 9e01f76..69021e8 100644 --- a/include/yaml-cpp/emitter.h +++ b/include/yaml-cpp/emitter.h @@ -82,6 +82,8 @@ namespace YAML void EmitKindTag(); void EmitTag(bool verbatim, const _Tag& tag); + bool CanEmitNewline() const; + private: ostream m_stream; std::auto_ptr m_pState; diff --git a/src/emitfromevents.cpp b/src/emitfromevents.cpp index ce9c2ac..4105a18 100644 --- a/src/emitfromevents.cpp +++ b/src/emitfromevents.cpp @@ -98,7 +98,7 @@ namespace YAML void EmitFromEvents::EmitProps(const std::string& tag, anchor_t anchor) { - if(!tag.empty()) + if(!tag.empty() && tag != "?") m_emitter << VerbatimTag(tag); if(anchor) m_emitter << Anchor(ToString(anchor)); diff --git a/src/emitter.cpp b/src/emitter.cpp index 3d50d3f..a2ad2a8 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -513,8 +513,19 @@ namespace YAML { if(!good()) return; - - m_stream << '\n'; + + if(CanEmitNewline()) + m_stream << '\n'; + } + + bool Emitter::CanEmitNewline() const + { + FLOW_TYPE flowType = m_pState->GetCurGroupFlowType(); + if(flowType == FT_BLOCK && m_pState->CurrentlyInLongKey()) + return true; + + EMITTER_STATE curState = m_pState->GetCurState(); + return curState != ES_DONE_WITH_BLOCK_MAP_KEY && curState != ES_WAITING_FOR_BLOCK_MAP_VALUE && curState != ES_WRITING_BLOCK_MAP_VALUE; } // ******************************************************************************************* diff --git a/test/emittertests.cpp b/test/emittertests.cpp index 057300c..cce4e01 100644 --- a/test/emittertests.cpp +++ b/test/emittertests.cpp @@ -673,7 +673,42 @@ namespace Test out << YAML::EndSeq; desiredOutput = "--- [a\n, b, c\n, d]"; } + + void NewlineInBlockMap(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << "a" << YAML::Value << "foo" << YAML::Newline; + out << YAML::Key << "b" << YAML::Newline << YAML::Value << "bar"; + out << YAML::LongKey << YAML::Key << "c" << YAML::Newline << YAML::Value << "car"; + out << YAML::EndMap; + desiredOutput = "---\na: foo\n\nb: bar\n? c\n\n: car"; + } + void NewlineInFlowMap(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Flow << YAML::BeginMap; + out << YAML::Key << "a" << YAML::Value << "foo" << YAML::Newline; + out << YAML::Key << "b" << YAML::Newline << YAML::Value << "bar"; + out << YAML::EndMap; + desiredOutput = "--- {a: foo\n, b\n: bar}"; + } + + void LotsOfNewlines(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << "a" << YAML::Newline; + out << YAML::BeginSeq; + out << "b" << "c" << YAML::Newline; + out << YAML::EndSeq; + out << YAML::Newline; + out << YAML::BeginMap; + out << YAML::Newline << YAML::Key << "d" << YAML::Value << YAML::Newline << "e"; + out << YAML::LongKey << YAML::Key << "f" << YAML::Newline << YAML::Value << "foo"; + out << YAML::EndMap; + out << YAML::EndSeq; + desiredOutput = "---\n- a\n\n-\n - b\n - c\n\n\n-\n\n d: e\n ? f\n\n : foo"; + } + //////////////////////////////////////////////////////////////////////////////////////////////////////// // incorrect emitting @@ -857,6 +892,9 @@ namespace Test RunEmitterTest(&Emitter::NewlineAtEnd, "newline at end", passed, total); RunEmitterTest(&Emitter::NewlineInBlockSequence, "newline in block sequence", passed, total); RunEmitterTest(&Emitter::NewlineInFlowSequence, "newline in flow sequence", passed, total); + RunEmitterTest(&Emitter::NewlineInBlockMap, "newline in block map", passed, total); + RunEmitterTest(&Emitter::NewlineInFlowMap, "newline in flow map", passed, total); + RunEmitterTest(&Emitter::LotsOfNewlines, "lots of newlines", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total); diff --git a/util/parse.cpp b/util/parse.cpp index 35b9dd2..f8cdb52 100644 --- a/util/parse.cpp +++ b/util/parse.cpp @@ -47,11 +47,10 @@ int main(int argc, char **argv) YAML::Parser parser(input); YAML::Node doc; NullEventHandler handler; -// while(parser.GetNextDocument(doc)) { - while(parser.HandleNextDocument(handler)) { -// YAML::Emitter emitter; -// emitter << doc; -// std::cout << emitter.c_str() << "\n"; + while(parser.GetNextDocument(doc)) { + YAML::Emitter emitter; + emitter << doc; + std::cout << emitter.c_str() << "\n"; } } catch(const YAML::Exception& e) { std::cerr << e.what() << "\n"; From d6e56a0941388a9f6ccbc79c3843de923374c3e3 Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 22 Oct 2010 04:19:01 +0000 Subject: [PATCH 236/295] Refactored emitter so that it emits the : for an implicit key right away --- src/emitter.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/emitter.cpp b/src/emitter.cpp index a2ad2a8..1b847e1 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -201,10 +201,6 @@ namespace YAML m_pState->SetError(ErrorMsg::EXPECTED_VALUE_TOKEN); return true; case ES_WAITING_FOR_BLOCK_MAP_VALUE: - if(m_pState->CurrentlyInLongKey()) - m_stream << IndentTo(curIndent); - m_stream << ':'; - m_pState->RequireSeparation(); m_pState->SwitchState(ES_WRITING_BLOCK_MAP_VALUE); return true; case ES_WRITING_BLOCK_MAP_VALUE: @@ -286,6 +282,10 @@ namespace YAML // block map case ES_WRITING_BLOCK_MAP_KEY: + if(!m_pState->CurrentlyInLongKey()) { + m_stream << ':'; + m_pState->RequireSeparation(); + } m_pState->SwitchState(ES_DONE_WITH_BLOCK_MAP_KEY); break; case ES_WRITING_BLOCK_MAP_VALUE: @@ -499,8 +499,12 @@ namespace YAML return m_pState->SetError(ErrorMsg::UNEXPECTED_VALUE_TOKEN); if(flowType == FT_BLOCK) { - if(m_pState->CurrentlyInLongKey()) + if(m_pState->CurrentlyInLongKey()) { m_stream << '\n'; + m_stream << IndentTo(m_pState->GetCurIndent()); + m_stream << ':'; + m_pState->RequireSeparation(); + } m_pState->SwitchState(ES_WAITING_FOR_BLOCK_MAP_VALUE); } else if(flowType == FT_FLOW) { m_pState->SwitchState(ES_WAITING_FOR_FLOW_MAP_VALUE); From 24dc58b68dee21bda42d497870f5bc96f07136d8 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 28 Oct 2010 21:53:54 +0000 Subject: [PATCH 237/295] Implemented binary emitting without the binary tag --- include/yaml-cpp/emitter.h | 2 ++ include/yaml-cpp/emittermanip.h | 10 +++++++++ src/emitter.cpp | 14 +++++++++++++ src/emitterutils.cpp | 37 +++++++++++++++++++++++++++++++++ src/emitterutils.h | 1 + test/emittertests.cpp | 21 +++++++++++++++++++ 6 files changed, 85 insertions(+) diff --git a/include/yaml-cpp/emitter.h b/include/yaml-cpp/emitter.h index 69021e8..a1980e9 100644 --- a/include/yaml-cpp/emitter.h +++ b/include/yaml-cpp/emitter.h @@ -53,6 +53,7 @@ namespace YAML Emitter& Write(const _Tag& tag); Emitter& Write(const _Comment& comment); Emitter& Write(const _Null& null); + Emitter& Write(const _Binary& binary); template Emitter& WriteIntegralType(T value); @@ -127,6 +128,7 @@ namespace YAML inline Emitter& operator << (Emitter& emitter, const _Tag& v) { return emitter.Write(v); } inline Emitter& operator << (Emitter& emitter, const _Comment& v) { return emitter.Write(v); } inline Emitter& operator << (Emitter& emitter, const _Null& v) { return emitter.Write(v); } + inline Emitter& operator << (Emitter& emitter, const _Binary& b) { return emitter.Write(b); } inline Emitter& operator << (Emitter& emitter, const char *v) { return emitter.Write(std::string(v)); } diff --git a/include/yaml-cpp/emittermanip.h b/include/yaml-cpp/emittermanip.h index a20bfb6..5ce0503 100644 --- a/include/yaml-cpp/emittermanip.h +++ b/include/yaml-cpp/emittermanip.h @@ -111,6 +111,16 @@ namespace YAML inline _Comment Comment(const std::string content) { return _Comment(content); } + + struct _Binary { + _Binary(const char *data_, std::size_t size_): data(data_), size(size_) {} + const char *data; + std::size_t size; + }; + + inline _Binary Binary(const char *data, std::size_t size) { + return _Binary(data, size); + } } #endif // EMITTERMANIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/emitter.cpp b/src/emitter.cpp index 1b847e1..91500a8 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -724,5 +724,19 @@ namespace YAML PostAtomicWrite(); return *this; } + + Emitter& Emitter::Write(const _Binary& binary) + { + if(!good()) + return *this; + + // TODO: write tag !!binary + + PreAtomicWrite(); + EmitSeparationIfNecessary(); + Utils::WriteBinary(m_stream, binary.data, binary.size); + PostAtomicWrite(); + return *this; + } } diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index 45e9f69..7bd03d8 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -313,6 +313,43 @@ namespace YAML out << ">"; return true; } + + bool WriteBinary(ostream& out, const char *data, std::size_t size) + { + static const char encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + const char PAD = '='; + + out << "\""; + std::size_t chunks = size / 3; + std::size_t remainder = size % 3; + + for(std::size_t i=0;i> 2]; + out << encoding[((data[0] & 0x3) << 4) | (data[1] >> 4)]; + out << encoding[((data[1] & 0xf) << 2) | (data[2] >> 6)]; + out << encoding[data[2] & 0x3f]; + } + + switch(remainder) { + case 0: + break; + case 1: + out << encoding[data[0] >> 2]; + out << encoding[((data[0] & 0x3) << 4)]; + out << PAD; + out << PAD; + break; + case 2: + out << encoding[data[0] >> 2]; + out << encoding[((data[0] & 0x3) << 4) | (data[1] >> 4)]; + out << encoding[((data[1] & 0xf) << 2)]; + out << PAD; + break; + } + + out << "\""; + return true; + } } } diff --git a/src/emitterutils.h b/src/emitterutils.h index 8e2356c..aa108c1 100644 --- a/src/emitterutils.h +++ b/src/emitterutils.h @@ -19,6 +19,7 @@ namespace YAML bool WriteAlias(ostream& out, const std::string& str); bool WriteAnchor(ostream& out, const std::string& str); bool WriteTag(ostream& out, const std::string& str, bool verbatim); + bool WriteBinary(ostream& out, const char *data, std::size_t size); } } diff --git a/test/emittertests.cpp b/test/emittertests.cpp index cce4e01..cfbac82 100644 --- a/test/emittertests.cpp +++ b/test/emittertests.cpp @@ -708,6 +708,24 @@ namespace Test out << YAML::EndSeq; desiredOutput = "---\n- a\n\n-\n - b\n - c\n\n\n-\n\n d: e\n ? f\n\n : foo"; } + + void Binary(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Binary("Hello, World!", 13); + desiredOutput = "--- !!binary \"SGVsbG8sIFdvcmxkIQ==\""; + } + + void LongBinary(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Binary("Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.\n", 270); + desiredOutput = "--- !!binary \"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4K\""; + } + + void EmptyBinary(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Binary("", 0); + desiredOutput = "--- !!binary \"\""; + } //////////////////////////////////////////////////////////////////////////////////////////////////////// // incorrect emitting @@ -895,6 +913,9 @@ namespace Test RunEmitterTest(&Emitter::NewlineInBlockMap, "newline in block map", passed, total); RunEmitterTest(&Emitter::NewlineInFlowMap, "newline in flow map", passed, total); RunEmitterTest(&Emitter::LotsOfNewlines, "lots of newlines", passed, total); + RunEmitterTest(&Emitter::Binary, "binary", passed, total); + RunEmitterTest(&Emitter::LongBinary, "long binary", passed, total); + RunEmitterTest(&Emitter::EmptyBinary, "empty binary", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total); From 8c913c8ce41169bb02ea3a2e7b4ade236377129c Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 28 Oct 2010 23:06:16 +0000 Subject: [PATCH 238/295] Refactored tags so we can emit secondary tags (and named local tags) --- include/yaml-cpp/emittermanip.h | 34 ++++++++++++++++++++------------- src/emitter.cpp | 32 +++++++++++++++++-------------- src/emitterutils.cpp | 30 +++++++++++++++++++++++++++++ src/emitterutils.h | 1 + 4 files changed, 70 insertions(+), 27 deletions(-) diff --git a/include/yaml-cpp/emittermanip.h b/include/yaml-cpp/emittermanip.h index 5ce0503..fc29655 100644 --- a/include/yaml-cpp/emittermanip.h +++ b/include/yaml-cpp/emittermanip.h @@ -84,24 +84,32 @@ namespace YAML } struct _Tag { - explicit _Tag(const std::string& content_) - : content(content_), verbatim(true) + struct Type { enum value { Verbatim, PrimaryHandle, NamedHandle }; }; + + explicit _Tag(const std::string& prefix_, const std::string& content_, Type::value type_) + : prefix(prefix_), content(content_), type(type_) { } + std::string prefix; std::string content; - bool verbatim; + Type::value type; }; - typedef _Tag VerbatimTag; - - struct LocalTag : public _Tag - { - explicit LocalTag(const std::string& content_) - : _Tag(content_) - { - verbatim = false; - } - }; + inline _Tag VerbatimTag(const std::string content) { + return _Tag("", content, _Tag::Type::Verbatim); + } + + inline _Tag LocalTag(const std::string content) { + return _Tag("", content, _Tag::Type::PrimaryHandle); + } + + inline _Tag LocalTag(const std::string& prefix, const std::string content) { + return _Tag(prefix, content, _Tag::Type::NamedHandle); + } + + inline _Tag SecondaryTag(const std::string content) { + return _Tag("", content, _Tag::Type::NamedHandle); + } struct _Comment { _Comment(const std::string& content_): content(content_) {} diff --git a/src/emitter.cpp b/src/emitter.cpp index 91500a8..30e422d 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -680,27 +680,31 @@ namespace YAML { if(!good()) return *this; - - EmitTag(tag.verbatim, tag); - return *this; - } - - void Emitter::EmitTag(bool verbatim, const _Tag& tag) - { + PreAtomicWrite(); EmitSeparationIfNecessary(); - if(!Utils::WriteTag(m_stream, tag.content, verbatim)) { + + bool success = false; + if(tag.type == _Tag::Type::Verbatim) + success = Utils::WriteTag(m_stream, tag.content, true); + else if(tag.type == _Tag::Type::PrimaryHandle) + success = Utils::WriteTag(m_stream, tag.content, false); + else + success = Utils::WriteTagWithPrefix(m_stream, tag.prefix, tag.content); + + if(!success) { m_pState->SetError(ErrorMsg::INVALID_TAG); - return; + return *this; } + m_pState->RequireSeparation(); // Note: no PostAtomicWrite() because we need another value for this node + return *this; } - + void Emitter::EmitKindTag() { - _Tag tag(""); - EmitTag(false, tag); + Write(LocalTag("")); } Emitter& Emitter::Write(const _Comment& comment) @@ -727,10 +731,10 @@ namespace YAML Emitter& Emitter::Write(const _Binary& binary) { + Write(SecondaryTag("binary")); + if(!good()) return *this; - - // TODO: write tag !!binary PreAtomicWrite(); EmitSeparationIfNecessary(); diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index 7bd03d8..38bd18f 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -314,6 +314,36 @@ namespace YAML return true; } + bool WriteTagWithPrefix(ostream& out, const std::string& prefix, const std::string& tag) + { + out << "!"; + StringCharSource prefixBuffer(prefix.c_str(), prefix.size()); + while(prefixBuffer) { + int n = Exp::URI().Match(prefixBuffer); + if(n <= 0) + return false; + + while(--n >= 0) { + out << prefixBuffer[0]; + ++prefixBuffer; + } + } + + out << "!"; + StringCharSource tagBuffer(tag.c_str(), tag.size()); + while(tagBuffer) { + int n = Exp::Tag().Match(tagBuffer); + if(n <= 0) + return false; + + while(--n >= 0) { + out << tagBuffer[0]; + ++tagBuffer; + } + } + return true; + } + bool WriteBinary(ostream& out, const char *data, std::size_t size) { static const char encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; diff --git a/src/emitterutils.h b/src/emitterutils.h index aa108c1..a44ae2c 100644 --- a/src/emitterutils.h +++ b/src/emitterutils.h @@ -19,6 +19,7 @@ namespace YAML bool WriteAlias(ostream& out, const std::string& str); bool WriteAnchor(ostream& out, const std::string& str); bool WriteTag(ostream& out, const std::string& str, bool verbatim); + bool WriteTagWithPrefix(ostream& out, const std::string& prefix, const std::string& tag); bool WriteBinary(ostream& out, const char *data, std::size_t size); } } From 6e06857bf9ec2e6b1b2d405fe83c0c5ec24070a2 Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 9 Nov 2010 19:59:25 +0000 Subject: [PATCH 239/295] Updated Visual Studio project file. --- yamlcpp.vcproj | 524 +++++++++++++++++++++++++++---------------------- 1 file changed, 288 insertions(+), 236 deletions(-) diff --git a/yamlcpp.vcproj b/yamlcpp.vcproj index aff65c7..6239819 100644 --- a/yamlcpp.vcproj +++ b/yamlcpp.vcproj @@ -156,114 +156,118 @@ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > - - - - - - - + - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Date: Mon, 15 Nov 2010 01:46:33 +0000 Subject: [PATCH 240/295] Added long long types to the emitter --- include/yaml-cpp/emitter.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/yaml-cpp/emitter.h b/include/yaml-cpp/emitter.h index a1980e9..c115dc2 100644 --- a/include/yaml-cpp/emitter.h +++ b/include/yaml-cpp/emitter.h @@ -138,6 +138,8 @@ namespace YAML inline Emitter& operator << (Emitter& emitter, unsigned short v) { return emitter.WriteIntegralType(v); } inline Emitter& operator << (Emitter& emitter, long v) { return emitter.WriteIntegralType(v); } inline Emitter& operator << (Emitter& emitter, unsigned long v) { return emitter.WriteIntegralType(v); } + inline Emitter& operator << (Emitter& emitter, long long v) { return emitter.WriteIntegralType(v); } + inline Emitter& operator << (Emitter& emitter, unsigned long long v) { return emitter.WriteIntegralType(v); } inline Emitter& operator << (Emitter& emitter, float v) { return emitter.WriteStreamable(v); } inline Emitter& operator << (Emitter& emitter, double v) { return emitter.WriteStreamable(v); } From 7fd040c311c60931f3531e4aec196b1e057779ed Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 3 Dec 2010 21:52:04 +0000 Subject: [PATCH 241/295] Fixed emitting colon at end of scalar bug --- CMakeLists.txt | 4 ++-- src/regeximpl.h | 8 +++++++- test/emittertests.cpp | 17 +++++++++++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 40154ec..893f137 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,8 +5,8 @@ project (YAML_CPP) set(LIB_TYPE SHARED) if(IPHONE) - set(CMAKE_OSX_SYSROOT iphoneos4.0) - set(CMAKE_OSX_ARCHITECTURES $(ARCHS_STANDARD_32_BIT)) + set(CMAKE_OSX_SYSROOT iphoneos4.2) + set(CMAKE_OSX_ARCHITECTURES "armv6;armv7") set(LIB_TYPE) endif(IPHONE) diff --git a/src/regeximpl.h b/src/regeximpl.h index 41a052e..c13f236 100644 --- a/src/regeximpl.h +++ b/src/regeximpl.h @@ -58,7 +58,13 @@ namespace YAML template<> inline bool RegEx::IsValidSource(const StringCharSource&source) const { - return source || m_op == REGEX_EMPTY; + switch(m_op) { + case REGEX_MATCH: + case REGEX_RANGE: + return source; + default: + return true; + } } template diff --git a/test/emittertests.cpp b/test/emittertests.cpp index cfbac82..b81ab68 100644 --- a/test/emittertests.cpp +++ b/test/emittertests.cpp @@ -726,6 +726,21 @@ namespace Test out << YAML::Binary("", 0); desiredOutput = "--- !!binary \"\""; } + + void ColonAtEndOfScalar(YAML::Emitter& out, std::string& desiredOutput) + { + out << "a:"; + desiredOutput = "--- \"a:\""; + } + + void ColonAsScalar(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << "apple" << YAML::Value << ":"; + out << YAML::Key << "banana" << YAML::Value << ":"; + out << YAML::EndMap; + desiredOutput = "---\napple: \":\"\nbanana: \":\""; + } //////////////////////////////////////////////////////////////////////////////////////////////////////// // incorrect emitting @@ -916,6 +931,8 @@ namespace Test RunEmitterTest(&Emitter::Binary, "binary", passed, total); RunEmitterTest(&Emitter::LongBinary, "long binary", passed, total); RunEmitterTest(&Emitter::EmptyBinary, "empty binary", passed, total); + RunEmitterTest(&Emitter::ColonAtEndOfScalar, "colon at end of scalar", passed, total); + RunEmitterTest(&Emitter::ColonAsScalar, "colon as scalar", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total); From 9e345650e116c355fad8e104fc088f15e211fcb0 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 31 Jan 2011 17:47:20 +0000 Subject: [PATCH 242/295] Added Anchor() regex (so that we're not just using Alphanumeric to match anchors), but it's still not 100% right (it shouldn't allow non-printable characters, e.g.). Also fixed a test that was broken along these lines (if a colon immediately follows an anchor, it's part of the anchor) --- src/exp.h | 4 ++++ src/scantoken.cpp | 2 +- test/parsertests.cpp | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/exp.h b/src/exp.h index 8b84214..c42daec 100644 --- a/src/exp.h +++ b/src/exp.h @@ -112,6 +112,10 @@ namespace YAML static const RegEx e = RegEx('#'); return e; } + inline const RegEx& Anchor() { + static const RegEx e = !(RegEx("[]{},", REGEX_OR) || BlankOrBreak()); + return e; + } inline const RegEx& AnchorEnd() { static const RegEx e = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak(); return e; diff --git a/src/scantoken.cpp b/src/scantoken.cpp index 82ea733..06d9cd6 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -238,7 +238,7 @@ namespace YAML alias = (indicator == Keys::Alias); // now eat the content - while(Exp::AlphaNumeric().Matches(INPUT)) + while(INPUT && Exp::Anchor().Matches(INPUT)) name += INPUT.get(); // we need to have read SOMETHING! diff --git a/test/parsertests.cpp b/test/parsertests.cpp index f013234..c432ef6 100644 --- a/test/parsertests.cpp +++ b/test/parsertests.cpp @@ -472,7 +472,7 @@ namespace Test bool AliasAsSimpleKey() { - std::string input = "- &a b\n- *a: c"; + std::string input = "- &a b\n- *a : c"; std::stringstream stream(input); YAML::Parser parser(stream); From 3f6254822dd6a656a8ab7528e82723d109523a05 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sat, 5 Feb 2011 22:28:08 +0000 Subject: [PATCH 243/295] Included cstddef to stream.h --- src/stream.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/stream.h b/src/stream.h index 952f6bf..7243fb6 100644 --- a/src/stream.h +++ b/src/stream.h @@ -6,11 +6,12 @@ #include "yaml-cpp/noncopyable.h" #include "yaml-cpp/mark.h" +#include #include #include -#include #include #include +#include namespace YAML { From 3192d29e6697f9f0135fe5fa9cafb39b13f0576f Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 2 Mar 2011 04:12:57 +0000 Subject: [PATCH 244/295] Switched exception constants to const char * const (from const std::string) so we don't have to construct them all in every translation unit, and switched the exception class to derive from std::runtime_error (so it handles what() for us) --- include/yaml-cpp/exceptions.h | 125 +++++++++++++++++----------------- src/exp.cpp | 2 +- src/parser.cpp | 2 +- test/parsertests.cpp | 6 +- test/spectests.cpp | 2 +- 5 files changed, 69 insertions(+), 68 deletions(-) diff --git a/include/yaml-cpp/exceptions.h b/include/yaml-cpp/exceptions.h index 7061626..402e284 100644 --- a/include/yaml-cpp/exceptions.h +++ b/include/yaml-cpp/exceptions.h @@ -6,7 +6,7 @@ #include "yaml-cpp/mark.h" #include "yaml-cpp/traits.h" -#include +#include #include #include @@ -15,59 +15,59 @@ namespace YAML // error messages namespace ErrorMsg { - const std::string YAML_DIRECTIVE_ARGS = "YAML directives must have exactly one argument"; - const std::string YAML_VERSION = "bad YAML version: "; - const std::string YAML_MAJOR_VERSION = "YAML major version too large"; - const std::string REPEATED_YAML_DIRECTIVE= "repeated YAML directive"; - const std::string TAG_DIRECTIVE_ARGS = "TAG directives must have exactly two arguments"; - const std::string REPEATED_TAG_DIRECTIVE = "repeated TAG directive"; - const std::string CHAR_IN_TAG_HANDLE = "illegal character found while scanning tag handle"; - const std::string TAG_WITH_NO_SUFFIX = "tag handle with no suffix"; - const std::string END_OF_VERBATIM_TAG = "end of verbatim tag not found"; - const std::string END_OF_MAP = "end of map not found"; - const std::string END_OF_MAP_FLOW = "end of map flow not found"; - const std::string END_OF_SEQ = "end of sequence not found"; - const std::string END_OF_SEQ_FLOW = "end of sequence flow not found"; - const std::string MULTIPLE_TAGS = "cannot assign multiple tags to the same node"; - const std::string MULTIPLE_ANCHORS = "cannot assign multiple anchors to the same node"; - const std::string MULTIPLE_ALIASES = "cannot assign multiple aliases to the same node"; - const std::string ALIAS_CONTENT = "aliases can't have any content, *including* tags"; - const std::string INVALID_HEX = "bad character found while scanning hex number"; - const std::string INVALID_UNICODE = "invalid unicode: "; - const std::string INVALID_ESCAPE = "unknown escape character: "; - const std::string UNKNOWN_TOKEN = "unknown token"; - const std::string DOC_IN_SCALAR = "illegal document indicator in scalar"; - const std::string EOF_IN_SCALAR = "illegal EOF in scalar"; - const std::string CHAR_IN_SCALAR = "illegal character in scalar"; - const std::string TAB_IN_INDENTATION = "illegal tab when looking for indentation"; - const std::string FLOW_END = "illegal flow end"; - const std::string BLOCK_ENTRY = "illegal block entry"; - const std::string MAP_KEY = "illegal map key"; - const std::string MAP_VALUE = "illegal map value"; - const std::string ALIAS_NOT_FOUND = "alias not found after *"; - const std::string ANCHOR_NOT_FOUND = "anchor not found after &"; - const std::string CHAR_IN_ALIAS = "illegal character found while scanning alias"; - const std::string CHAR_IN_ANCHOR = "illegal character found while scanning anchor"; - const std::string ZERO_INDENT_IN_BLOCK = "cannot set zero indentation for a block scalar"; - const std::string CHAR_IN_BLOCK = "unexpected character in block scalar"; - const std::string AMBIGUOUS_ANCHOR = "cannot assign the same alias to multiple nodes"; - const std::string UNKNOWN_ANCHOR = "the referenced anchor is not defined"; + const char * const YAML_DIRECTIVE_ARGS = "YAML directives must have exactly one argument"; + const char * const YAML_VERSION = "bad YAML version: "; + const char * const YAML_MAJOR_VERSION = "YAML major version too large"; + const char * const REPEATED_YAML_DIRECTIVE= "repeated YAML directive"; + const char * const TAG_DIRECTIVE_ARGS = "TAG directives must have exactly two arguments"; + const char * const REPEATED_TAG_DIRECTIVE = "repeated TAG directive"; + const char * const CHAR_IN_TAG_HANDLE = "illegal character found while scanning tag handle"; + const char * const TAG_WITH_NO_SUFFIX = "tag handle with no suffix"; + const char * const END_OF_VERBATIM_TAG = "end of verbatim tag not found"; + const char * const END_OF_MAP = "end of map not found"; + const char * const END_OF_MAP_FLOW = "end of map flow not found"; + const char * const END_OF_SEQ = "end of sequence not found"; + const char * const END_OF_SEQ_FLOW = "end of sequence flow not found"; + const char * const MULTIPLE_TAGS = "cannot assign multiple tags to the same node"; + const char * const MULTIPLE_ANCHORS = "cannot assign multiple anchors to the same node"; + const char * const MULTIPLE_ALIASES = "cannot assign multiple aliases to the same node"; + const char * const ALIAS_CONTENT = "aliases can't have any content, *including* tags"; + const char * const INVALID_HEX = "bad character found while scanning hex number"; + const char * const INVALID_UNICODE = "invalid unicode: "; + const char * const INVALID_ESCAPE = "unknown escape character: "; + const char * const UNKNOWN_TOKEN = "unknown token"; + const char * const DOC_IN_SCALAR = "illegal document indicator in scalar"; + const char * const EOF_IN_SCALAR = "illegal EOF in scalar"; + const char * const CHAR_IN_SCALAR = "illegal character in scalar"; + const char * const TAB_IN_INDENTATION = "illegal tab when looking for indentation"; + const char * const FLOW_END = "illegal flow end"; + const char * const BLOCK_ENTRY = "illegal block entry"; + const char * const MAP_KEY = "illegal map key"; + const char * const MAP_VALUE = "illegal map value"; + const char * const ALIAS_NOT_FOUND = "alias not found after *"; + const char * const ANCHOR_NOT_FOUND = "anchor not found after &"; + const char * const CHAR_IN_ALIAS = "illegal character found while scanning alias"; + const char * const CHAR_IN_ANCHOR = "illegal character found while scanning anchor"; + const char * const ZERO_INDENT_IN_BLOCK = "cannot set zero indentation for a block scalar"; + const char * const CHAR_IN_BLOCK = "unexpected character in block scalar"; + const char * const AMBIGUOUS_ANCHOR = "cannot assign the same alias to multiple nodes"; + const char * const UNKNOWN_ANCHOR = "the referenced anchor is not defined"; - const std::string INVALID_SCALAR = "invalid scalar"; - const std::string KEY_NOT_FOUND = "key not found"; - const std::string BAD_DEREFERENCE = "bad dereference"; + const char * const INVALID_SCALAR = "invalid scalar"; + const char * const KEY_NOT_FOUND = "key not found"; + const char * const BAD_DEREFERENCE = "bad dereference"; - const std::string UNMATCHED_GROUP_TAG = "unmatched group tag"; - const std::string UNEXPECTED_END_SEQ = "unexpected end sequence token"; - const std::string UNEXPECTED_END_MAP = "unexpected end map token"; - const std::string SINGLE_QUOTED_CHAR = "invalid character in single-quoted string"; - const std::string INVALID_ANCHOR = "invalid anchor"; - const std::string INVALID_ALIAS = "invalid alias"; - const std::string INVALID_TAG = "invalid tag"; - const std::string EXPECTED_KEY_TOKEN = "expected key token"; - const std::string EXPECTED_VALUE_TOKEN = "expected value token"; - const std::string UNEXPECTED_KEY_TOKEN = "unexpected key token"; - const std::string UNEXPECTED_VALUE_TOKEN = "unexpected value token"; + const char * const UNMATCHED_GROUP_TAG = "unmatched group tag"; + const char * const UNEXPECTED_END_SEQ = "unexpected end sequence token"; + const char * const UNEXPECTED_END_MAP = "unexpected end map token"; + const char * const SINGLE_QUOTED_CHAR = "invalid character in single-quoted string"; + const char * const INVALID_ANCHOR = "invalid anchor"; + const char * const INVALID_ALIAS = "invalid alias"; + const char * const INVALID_TAG = "invalid tag"; + const char * const EXPECTED_KEY_TOKEN = "expected key token"; + const char * const EXPECTED_VALUE_TOKEN = "expected value token"; + const char * const UNEXPECTED_KEY_TOKEN = "unexpected key token"; + const char * const UNEXPECTED_VALUE_TOKEN = "unexpected value token"; template inline const std::string KEY_NOT_FOUND_WITH_KEY(const T&, typename disable_if >::type * = 0) { @@ -75,7 +75,9 @@ namespace YAML } inline const std::string KEY_NOT_FOUND_WITH_KEY(const std::string& key) { - return KEY_NOT_FOUND + ": " + key; + std::stringstream stream; + stream << KEY_NOT_FOUND << ": " << key; + return stream.str(); } template @@ -86,22 +88,21 @@ namespace YAML } } - class Exception: public std::exception { + class Exception: public std::runtime_error { public: Exception(const Mark& mark_, const std::string& msg_) - : mark(mark_), msg(msg_) { - std::stringstream output; - output << "yaml-cpp: error at line " << mark.line+1 << ", column " << mark.column+1 << ": " << msg; - what_ = output.str(); - } + : std::runtime_error(build_what(mark_, msg_)), mark(mark_), msg(msg_) {} virtual ~Exception() throw() {} - virtual const char *what() const throw() { return what_.c_str(); } Mark mark; std::string msg; - + private: - std::string what_; + static const std::string build_what(const Mark& mark, const std::string& msg) { + std::stringstream output; + output << "yaml-cpp: error at line " << mark.line+1 << ", column " << mark.column+1 << ": " << msg; + return output.str(); + } }; class ParserException: public Exception { diff --git a/src/exp.cpp b/src/exp.cpp index a23f441..7bc5454 100644 --- a/src/exp.cpp +++ b/src/exp.cpp @@ -107,7 +107,7 @@ namespace YAML } std::stringstream msg; - throw ParserException(in.mark(), ErrorMsg::INVALID_ESCAPE + ch); + throw ParserException(in.mark(), std::string(ErrorMsg::INVALID_ESCAPE) + ch); } } } diff --git a/src/parser.cpp b/src/parser.cpp index 01afbd7..b24c389 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -112,7 +112,7 @@ namespace YAML str.get(); str >> m_pDirectives->version.minor; if(!str || str.peek() != EOF) - throw ParserException(token.mark, ErrorMsg::YAML_VERSION + token.params[0]); + throw ParserException(token.mark, std::string(ErrorMsg::YAML_VERSION) + token.params[0]); if(m_pDirectives->version.major > 1) throw ParserException(token.mark, ErrorMsg::YAML_MAJOR_VERSION); diff --git a/test/parsertests.cpp b/test/parsertests.cpp index c432ef6..9393208 100644 --- a/test/parsertests.cpp +++ b/test/parsertests.cpp @@ -669,21 +669,21 @@ namespace Test try { doc["bad key"]; } catch(const YAML::Exception& e) { - if(e.msg != YAML::ErrorMsg::KEY_NOT_FOUND + ": bad key") + if(e.msg != std::string(YAML::ErrorMsg::KEY_NOT_FOUND) + ": bad key") throw; } try { doc[5]; } catch(const YAML::Exception& e) { - if(e.msg != YAML::ErrorMsg::KEY_NOT_FOUND + ": 5") + if(e.msg != std::string(YAML::ErrorMsg::KEY_NOT_FOUND) + ": 5") throw; } try { doc[2.5]; } catch(const YAML::Exception& e) { - if(e.msg != YAML::ErrorMsg::KEY_NOT_FOUND + ": 2.5") + if(e.msg != std::string(YAML::ErrorMsg::KEY_NOT_FOUND) + ": 2.5") throw; } diff --git a/test/spectests.cpp b/test/spectests.cpp index d809b69..106de80 100644 --- a/test/spectests.cpp +++ b/test/spectests.cpp @@ -888,7 +888,7 @@ namespace Test { YAML::Node doc; parser.GetNextDocument(doc); } catch(const YAML::ParserException& e) { - YAML_ASSERT(e.msg == YAML::ErrorMsg::INVALID_ESCAPE + "c"); + YAML_ASSERT(e.msg == std::string(YAML::ErrorMsg::INVALID_ESCAPE) + "c"); return true; } From 0823af5369a8b91941803f18fd5a090a8bd6aabd Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 2 Mar 2011 04:37:55 +0000 Subject: [PATCH 245/295] Merged CMakeLists.txt from issue 87 - now it's cleaner, and supports Windows much better --- CMakeLists.txt | 326 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 244 insertions(+), 82 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 893f137..763b02a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,82 +1,244 @@ -cmake_minimum_required(VERSION 2.6) - -project (YAML_CPP) - -set(LIB_TYPE SHARED) - -if(IPHONE) - set(CMAKE_OSX_SYSROOT iphoneos4.2) - set(CMAKE_OSX_ARCHITECTURES "armv6;armv7") - set(LIB_TYPE) -endif(IPHONE) - -if(CMAKE_COMPILER_IS_GNUCC) - set(CMAKE_CXX_FLAGS "-O2 -Wall -Wextra -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}") -endif(CMAKE_COMPILER_IS_GNUCC) - -if(MSVC) - set(LIB_TYPE) # I can't figure out how CMake handles Windows shared libraries - set(CMAKE_CXX_FLAGS "/W3 /wd4127 /wd4355 /D_SCL_SECURE_NO_WARNINGS ${CMAKE_CXX_FLAGS}") -endif(MSVC) - -set(YAML_CPP_VERSION_MAJOR "0") -set(YAML_CPP_VERSION_MINOR "2") -set(YAML_CPP_VERSION_PATCH "5") -set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}") - -enable_testing() - -option(YAML_CPP_BUILD_TOOLS "Enables or disables testing and parse tools" true) - -if(WIN32) - set(_library_dir bin) # .dll are in PATH, like executables -else(WIN32) - set(_library_dir lib) -endif(WIN32) - -set(INCLUDE_INSTALL_DIR include/yaml-cpp) -set(LIB_INSTALL_DIR ${_library_dir}${LIB_SUFFIX}) - -# -set(_INSTALL_DESTINATIONS - RUNTIME DESTINATION bin - LIBRARY DESTINATION ${LIB_INSTALL_DIR} - ARCHIVE DESTINATION lib${LIB_SUFFIX} -) -# -file(GLOB public_headers include/yaml-cpp/[a-z]*.h) -file(GLOB private_headers src/[a-z]*.h) -file(GLOB sources src/[a-z]*.cpp) - -include_directories(${YAML_CPP_SOURCE_DIR}/include) -add_library(yaml-cpp - ${LIB_TYPE} - ${public_headers} - ${private_headers} - ${sources} -) -set_target_properties(yaml-cpp PROPERTIES - VERSION "${YAML_CPP_VERSION}" - SOVERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}" -) - -if(IPHONE) -set_target_properties(yaml-cpp PROPERTIES XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "3.0") -endif(IPHONE) - -install(TARGETS yaml-cpp ${_INSTALL_DESTINATIONS}) -install( - FILES ${public_headers} - DESTINATION ${INCLUDE_INSTALL_DIR} -) - -if(UNIX) - set(PC_FILE ${CMAKE_BINARY_DIR}/yaml-cpp.pc) - configure_file("yaml-cpp.pc.cmake" ${PC_FILE} @ONLY) - install(FILES ${PC_FILE} DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) -endif(UNIX) - -if(YAML_CPP_BUILD_TOOLS) - add_subdirectory (test) - add_subdirectory (util) -endif(YAML_CPP_BUILD_TOOLS) +### +### CMake settings +### +## Due to Mac OSX we need to keep compatibility with CMake 2.6 +# see http://www.cmake.org/Wiki/CMake_Policies +cmake_minimum_required(VERSION 2.6) +# see http://www.cmake.org/cmake/help/cmake-2-8-docs.html#policy:CMP0012 +if(POLICY CMP0012) + cmake_policy(SET CMP0012 OLD) +endif() +# see http://www.cmake.org/cmake/help/cmake-2-8-docs.html#policy:CMP0015 +if(POLICY CMP0015) + cmake_policy(SET CMP0015 OLD) +endif() + +include(CheckCXXCompilerFlag) + + +### +### Project settings +### +project(YAML_CPP) + +set(YAML_CPP_VERSION_MAJOR "0") +set(YAML_CPP_VERSION_MINOR "2") +set(YAML_CPP_VERSION_PATCH "5") +set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}") + +enable_testing() + + +### +### Project options +### +## Project stuff +option(YAML_CPP_BUILD_TOOLS "Enable testing and parse tools" ON) + +## Build options +# --> General +# see http://www.cmake.org/cmake/help/cmake2.6docs.html#variable:BUILD_SHARED_LIBS +# http://www.cmake.org/cmake/help/cmake2.6docs.html#command:add_library +option(BUILD_SHARED_LIBS "Build Shared Libraries" OFF) + +# --> Apple +option(APPLE_UNIVERSAL_BIN "Apple: Build universal binary" OFF) + +# --> Microsoft Visual C++ +# see http://msdn.microsoft.com/en-us/library/aa278396(v=VS.60).aspx +# http://msdn.microsoft.com/en-us/library/2kzt1wy3(v=VS.71).aspx +option(MSVC_SHARED_RT "MSVC: Build with shared runtime libs (/MD)" ON) +option(MSVC_STHREADED_RT "MSVC: Build with single-threaded static runtime libs (/ML until VS .NET 2003)" OFF) + + +### +### Sources, headers, directories and libs +### +file(GLOB sources "src/[a-zA-Z]*.cpp") +file(GLOB public_headers "include/yaml-cpp/[a-zA-Z]*.h") +file(GLOB private_headers "src/[a-zA-Z]*.h") + +if(VERBOSE) + message(STATUS "sources: ${sources}") + message(STATUS "public_headers: ${public_headers}") + message(STATUS "private_headers: ${private_headers}") +endif() + +include_directories(${YAML_CPP_SOURCE_DIR}/include) + + +### +### General compilation settings +### +if(BUILD_SHARED_LIBS) + set(LABEL_SUFFIX "shared") +else() + set(LABEL_SUFFIX "static") +endif() + +if(APPLE) + if(APPLE_UNIVERSAL_BIN) + set(CMAKE_OSX_ARCHITECTURES ppc;i386) + endif() +endif() + +if(IPHONE) + set(CMAKE_OSX_SYSROOT "iphoneos4.2") + set(CMAKE_OSX_ARCHITECTURES "armv6;armv7") +endif() + +if(WIN32) + if(BUILD_SHARED_LIBS) + add_definitions(-D${PROJECT_NAME}_DLL) # use or build Windows DLL + endif() + if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "C:/") + endif() +endif() + +# GCC specialities +if(CMAKE_COMPILER_IS_GNUCXX) + ### General stuff + if(WIN32) + set(CMAKE_SHARED_LIBRARY_PREFIX "") # DLLs do not have a "lib" prefix + set(CMAKE_IMPORT_LIBRARY_PREFIX "") # same for DLL import libs + set(CMAKE_LINK_DEF_FILE_FLAG "") # CMake workaround (2.8.3) + endif() + + ### Project stuff + set(GCC_EXTRA_OPTIONS "") + # + set(FLAG_TESTED "-Wextra") + check_cxx_compiler_flag(${FLAG_TESTED} FLAG_WEXTRA) + if(FLAG_WEXTRA) + set(GCC_EXTRA_OPTIONS "${GCC_EXTRA_OPTIONS} ${FLAG_TESTED}") + endif() + # + set(CMAKE_CXX_FLAGS "-O2 -Wall ${GCC_EXTRA_OPTIONS} -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}") +endif() + +# Microsoft VisualC++ specialities +if(MSVC) + ### General stuff + # a) Change MSVC runtime library settings (/MD[d], /MT[d], /ML[d] (single-threaded until VS 2003)) + # plus set lib suffix for later use and project label accordingly + # see http://msdn.microsoft.com/en-us/library/aa278396(v=VS.60).aspx + # http://msdn.microsoft.com/en-us/library/2kzt1wy3(v=VS.71).aspx + set(LIB_RT_SUFFIX "md") # CMake defaults to /MD for MSVC + set(LIB_RT_OPTION "/MD") + # + if(NOT MSVC_SHARED_RT) # User wants to have static runtime libraries (/MT, /ML) + if(MSVC_STHREADED_RT) # User wants to have old single-threaded static runtime libraries + set(LIB_RT_SUFFIX "ml") + set(LIB_RT_OPTION "/ML") + if(NOT ${MSVC_VERSION} LESS 1400) + message(FATAL_ERROR "Single-threaded static runtime libraries (/ML) only available until VS .NET 2003 (7.1).") + endif() + else() + set(LIB_RT_SUFFIX "mt") + set(LIB_RT_OPTION "/MT") + endif() + + # correct linker options + foreach(flag_var CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + foreach(config_name "" DEBUG RELEASE MINSIZEREL RELWITHDEBINFO) + set(var_name "${flag_var}") + if(NOT "${config_name}" STREQUAL "") + set(var_name "${var_name}_${config_name}") + endif() + string(REPLACE "/MD" "${LIB_RT_OPTION}" ${var_name} "${${var_name}}") + endforeach() + endforeach() + endif() + # + set(LABEL_SUFFIX "${LABEL_SUFFIX} ${LIB_RT_OPTION}") + + # b) Change prefix for static libraries + set(CMAKE_STATIC_LIBRARY_PREFIX "lib") # to distinguish static libraries from DLL import libs + + # c) Correct suffixes for static libraries + if(NOT BUILD_SHARED_LIBS) + ### General stuff + set(LIB_TARGET_SUFFIX "${LIB_SUFFIX}${LIB_RT_SUFFIX}") + endif() + + ### Project stuff + # /W3 = set warning level; see http://msdn.microsoft.com/en-us/library/thxezb7y.aspx + # /wd4127 = disable warning C4127 "conditional expression is constant"; see http://msdn.microsoft.com/en-us/library/6t66728h.aspx + # /wd4355 = disable warning C4355 "'this' : used in base member initializer list"; http://msdn.microsoft.com/en-us/library/3c594ae3.aspx + set(CMAKE_CXX_FLAGS "/W3 /wd4127 /wd4355 /D_SCL_SECURE_NO_WARNINGS ${CMAKE_CXX_FLAGS}") +endif() + + +### +### General install settings +### +if(WIN32) + set(_library_dir bin) # .dll are in PATH, like executables +else() + set(_library_dir lib) +endif() + +set(INCLUDE_INSTALL_DIR include/yaml-cpp) +set(LIB_INSTALL_DIR "${_library_dir}${LIB_SUFFIX}") + +set(_INSTALL_DESTINATIONS + RUNTIME DESTINATION bin + LIBRARY DESTINATION ${LIB_INSTALL_DIR} + ARCHIVE DESTINATION "lib${LIB_SUFFIX}" +) + + +### +### Library +### +add_library(yaml-cpp + ${sources} + ${public_headers} + ${private_headers} +) + +set_target_properties(yaml-cpp PROPERTIES + VERSION "${YAML_CPP_VERSION}" + SOVERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}" + PROJECT_LABEL "yaml-cpp ${LABEL_SUFFIX}" +) + +if(IPHONE) + set_target_properties(yaml-cpp PROPERTIES + XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "3.0" + ) +endif() + +if(MSVC) + if(NOT BUILD_SHARED_LIBS) + # correct library names + set_target_properties(yaml-cpp PROPERTIES + DEBUG_POSTFIX "${LIB_TARGET_SUFFIX}d" + RELEASE_POSTFIX "${LIB_TARGET_SUFFIX}" + MINSIZEREL_POSTFIX "${LIB_TARGET_SUFFIX}" + RELWITHDEBINFO_POSTFIX "${LIB_TARGET_SUFFIX}" + ) + endif() +endif() + +install(TARGETS yaml-cpp ${_INSTALL_DESTINATIONS}) +install( + FILES ${public_headers} + DESTINATION ${INCLUDE_INSTALL_DIR} +) + +if(UNIX) + set(PC_FILE ${CMAKE_BINARY_DIR}/yaml-cpp.pc) + configure_file("yaml-cpp.pc.cmake" ${PC_FILE} @ONLY) + install(FILES ${PC_FILE} DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) +endif() + + +### +### Extras +### +if(YAML_CPP_BUILD_TOOLS) + add_subdirectory(test) + add_subdirectory(util) +endif() From 7b6e87277d8fa8a446e2c6a2fee2cf2c1abd72ea Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 2 Mar 2011 04:48:04 +0000 Subject: [PATCH 246/295] Merged contrib folders from the graphbuilder-api branch, including the recursive search in CMakeLists.txt --- CMakeLists.txt | 6 +- include/yaml-cpp/contrib/anchordict.h | 40 ++++++++ include/yaml-cpp/contrib/graphbuilder.h | 129 ++++++++++++++++++++++++ src/contrib/graphbuilder.cpp | 16 +++ src/contrib/graphbuilderadapter.cpp | 96 ++++++++++++++++++ src/contrib/graphbuilderadapter.h | 68 +++++++++++++ 6 files changed, 352 insertions(+), 3 deletions(-) create mode 100644 include/yaml-cpp/contrib/anchordict.h create mode 100644 include/yaml-cpp/contrib/graphbuilder.h create mode 100644 src/contrib/graphbuilder.cpp create mode 100644 src/contrib/graphbuilderadapter.cpp create mode 100644 src/contrib/graphbuilderadapter.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 763b02a..dd91a24 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,9 +54,9 @@ option(MSVC_STHREADED_RT "MSVC: Build with single-threaded static runtime libs ( ### ### Sources, headers, directories and libs ### -file(GLOB sources "src/[a-zA-Z]*.cpp") -file(GLOB public_headers "include/yaml-cpp/[a-zA-Z]*.h") -file(GLOB private_headers "src/[a-zA-Z]*.h") +file(GLOB_RECURSE sources "src/[a-zA-Z]*.cpp") +file(GLOB_RECURSE public_headers "include/yaml-cpp/[a-zA-Z]*.h") +file(GLOB_RECURSE private_headers "src/[a-zA-Z]*.h") if(VERBOSE) message(STATUS "sources: ${sources}") diff --git a/include/yaml-cpp/contrib/anchordict.h b/include/yaml-cpp/contrib/anchordict.h new file mode 100644 index 0000000..fef8e9a --- /dev/null +++ b/include/yaml-cpp/contrib/anchordict.h @@ -0,0 +1,40 @@ +#pragma once + +#ifndef ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#include + +#include "../anchor.h" + +namespace YAML +{ + /// AnchorDict + /// . An object that stores and retrieves values correlating to anchor_t + /// values. + /// . Efficient implementation that can make assumptions about how anchor_t + /// values are assigned by the Parser class. + template + class AnchorDict + { + public: + void Register(anchor_t anchor, T value) + { + if (anchor > m_data.size()) + { + m_data.resize(anchor); + } + m_data[anchor - 1] = value; + } + + T Get(anchor_t anchor) const + { + return m_data[anchor - 1]; + } + + private: + std::vector m_data; + }; +} + +#endif // ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/contrib/graphbuilder.h b/include/yaml-cpp/contrib/graphbuilder.h new file mode 100644 index 0000000..6b26b40 --- /dev/null +++ b/include/yaml-cpp/contrib/graphbuilder.h @@ -0,0 +1,129 @@ +#ifndef GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#include + +namespace YAML +{ + struct Mark; + class Parser; + + // 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 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(m_impl.NewNull(tag, AsNode(pParentNode))); + } + + virtual void *NewScalar(const Mark& mark, const std::string& tag, void *pParentNode, const std::string& value) { + return CheckType(m_impl.NewScalar(mark, tag, AsNode(pParentNode), value)); + } + + virtual void *NewSequence(const Mark& mark, const std::string& tag, void *pParentNode) { + return CheckType(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(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(m_impl.AnchorReference(mark, AsNode(pNode))); + } + + private: + Impl& m_impl; + + // Static check for pointer to T + template + static T* CheckType(U* p) {return p;} + + static Node *AsNode(void *pNode) {return static_cast(pNode);} + static Sequence *AsSequence(void *pSeq) {return static_cast(pSeq);} + static Map *AsMap(void *pMap) {return static_cast(pMap);} + }; + + void *BuildGraphOfNextDocument(Parser& parser, GraphBuilderInterface& graphBuilder); + + template + typename Impl::Node *BuildGraphOfNextDocument(Parser& parser, Impl& impl) + { + GraphBuilder graphBuilder(impl); + return static_cast(BuildGraphOfNextDocument( + parser, graphBuilder + )); + } +} + +#endif // GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/contrib/graphbuilder.cpp b/src/contrib/graphbuilder.cpp new file mode 100644 index 0000000..424b302 --- /dev/null +++ b/src/contrib/graphbuilder.cpp @@ -0,0 +1,16 @@ +#include "yaml-cpp/parser.h" +#include "yaml-cpp/contrib/graphbuilder.h" +#include "graphbuilderadapter.h" + +namespace YAML +{ + void *BuildGraphOfNextDocument(Parser& parser, GraphBuilderInterface& graphBuilder) + { + GraphBuilderAdapter eventHandler(graphBuilder); + if (parser.HandleNextDocument(eventHandler)) { + return eventHandler.RootNode(); + } else { + return NULL; + } + } +} \ No newline at end of file diff --git a/src/contrib/graphbuilderadapter.cpp b/src/contrib/graphbuilderadapter.cpp new file mode 100644 index 0000000..6431a45 --- /dev/null +++ b/src/contrib/graphbuilderadapter.cpp @@ -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.Get(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.Register(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); + } + } +} diff --git a/src/contrib/graphbuilderadapter.h b/src/contrib/graphbuilderadapter.h new file mode 100644 index 0000000..05a0b3a --- /dev/null +++ b/src/contrib/graphbuilderadapter.h @@ -0,0 +1,68 @@ +#ifndef GRAPHBUILDERADAPTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define GRAPHBUILDERADAPTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#include +#include +#include "yaml-cpp/eventhandler.h" +#include "yaml-cpp/contrib/anchordict.h" +#include "yaml-cpp/contrib/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 ContainerStack; + typedef AnchorDict 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 From 898d29d9b707ecd36732e36d42000f9360fe1729 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 2 Mar 2011 05:02:01 +0000 Subject: [PATCH 247/295] Merged the debuggable branch's CMakeLists.txt (and added a build for RelWithDebInfo) - note that the options are only for gcc --- CMakeLists.txt | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dd91a24..7807494 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,7 +106,14 @@ if(CMAKE_COMPILER_IS_GNUCXX) endif() ### Project stuff - set(GCC_EXTRA_OPTIONS "") + if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) + endif() + set(GCC_EXTRA_OPTIONS "") + # + set(CMAKE_CXX_FLAGS_RELEASE "-O2") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") + set(CMAKE_CXX_FLAGS_DEBUG "-g") # set(FLAG_TESTED "-Wextra") check_cxx_compiler_flag(${FLAG_TESTED} FLAG_WEXTRA) @@ -114,7 +121,16 @@ if(CMAKE_COMPILER_IS_GNUCXX) set(GCC_EXTRA_OPTIONS "${GCC_EXTRA_OPTIONS} ${FLAG_TESTED}") endif() # - set(CMAKE_CXX_FLAGS "-O2 -Wall ${GCC_EXTRA_OPTIONS} -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}") + set(CMAKE_CXX_FLAGS "-Wall ${GCC_EXTRA_OPTIONS} -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}") + # + add_custom_target(debuggable $(MAKE) clean + COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug ${CMAKE_SOURCE_DIR} + COMMENT "Adjusting settings for debug compilation" + VERBATIM) + add_custom_target(releasable $(MAKE) clean + COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Release ${CMAKE_SOURCE_DIR} + COMMENT "Adjusting settings for release compilation" + VERBATIM) endif() # Microsoft VisualC++ specialities From 357cd1e1221aba511e704362508b9832a7b7f237 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 2 Mar 2011 05:15:36 +0000 Subject: [PATCH 248/295] Fixed 'long long' error in VS 2002, issue 90 --- include/yaml-cpp/traits.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/yaml-cpp/traits.h b/include/yaml-cpp/traits.h index 46db01b..e9c42ad 100644 --- a/include/yaml-cpp/traits.h +++ b/include/yaml-cpp/traits.h @@ -17,8 +17,13 @@ namespace YAML template <> struct is_numeric { enum { value = true }; }; template <> struct is_numeric { enum { value = true }; }; template <> struct is_numeric { enum { value = true }; }; +#if defined(_MSC_VER) && (_MSC_VER < 1310) + template <> struct is_numeric <__int64> { enum { value = true }; }; + template <> struct is_numeric { enum { value = true }; }; +#else template <> struct is_numeric { enum { value = true }; }; template <> struct is_numeric { enum { value = true }; }; +#endif template <> struct is_numeric { enum { value = true }; }; template <> struct is_numeric { enum { value = true }; }; template <> struct is_numeric { enum { value = true }; }; From fb3b49173458747eca3a8561e73f5963afc76193 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 2 Mar 2011 05:21:25 +0000 Subject: [PATCH 249/295] Moved the local structs from Emitter::Write(bool) to an anonymous namespace in the hopes that Visual Studio <= 2003 will be happy --- src/emitter.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/emitter.cpp b/src/emitter.cpp index 30e422d..03555ea 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -605,6 +605,12 @@ namespace YAML m_stream << str.str(); PostAtomicWrite(); } + + namespace { + struct BoolName { std::string trueName, falseName; }; + struct BoolFormatNames { BoolName upper, lower, camel; }; + struct BoolTypes { BoolFormatNames yesNo, trueFalse, onOff; }; + } Emitter& Emitter::Write(bool b) { @@ -615,10 +621,6 @@ namespace YAML EmitSeparationIfNecessary(); // set up all possible bools to write - struct BoolName { std::string trueName, falseName; }; - struct BoolFormatNames { BoolName upper, lower, camel; }; - struct BoolTypes { BoolFormatNames yesNo, trueFalse, onOff; }; - static const BoolTypes boolTypes = { { { "YES", "NO" }, { "yes", "no" }, { "Yes", "No" } }, { { "TRUE", "FALSE" }, { "true", "false" }, { "True", "False" } }, From f4d2f11d2cddaa8cdd8774b8fbf2e80a7943d223 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 2 Mar 2011 05:29:46 +0000 Subject: [PATCH 250/295] Small changes to eliminate compiler warnings for 'nite' in issue 83 --- src/node.cpp | 3 ++- src/scanner.cpp | 1 + src/tag.cpp | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/node.cpp b/src/node.cpp index 7828ce5..a17eefa 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -25,8 +25,9 @@ namespace YAML return *pNode1 < *pNode2; } - Node::Node(): m_type(CT_NONE), m_pContent(0), m_alias(false), m_pIdentity(this), m_referenced(false) + Node::Node(): m_type(CT_NONE), m_pContent(0), m_alias(false), m_referenced(false) { + m_pIdentity = this; } Node::~Node() diff --git a/src/scanner.cpp b/src/scanner.cpp index eb211f7..da89ac1 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -271,6 +271,7 @@ namespace YAML case IndentMarker::NONE: assert(false); break; } assert(false); + throw std::runtime_error("yaml-cpp: internal error, invalid indent type"); } // PushIndentTo diff --git a/src/tag.cpp b/src/tag.cpp index 30d68e1..82a4704 100644 --- a/src/tag.cpp +++ b/src/tag.cpp @@ -2,6 +2,7 @@ #include "directives.h" #include "token.h" #include +#include namespace YAML { @@ -45,6 +46,7 @@ namespace YAML default: assert(false); } + throw std::runtime_error("yaml-cpp: internal error, bad tag type"); } } From 142a4bca9b66e21fd2949b4fbd9fa8ec1b496f6b Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 2 Mar 2011 06:11:41 +0000 Subject: [PATCH 251/295] Flipped the include guard and the pragma, and don't use the pragma for early versions of gcc (< 3.4) --- include/yaml-cpp/aliasmanager.h | 6 ++++-- include/yaml-cpp/anchor.h | 6 ++++-- include/yaml-cpp/contrib/anchordict.h | 6 ++++-- include/yaml-cpp/contrib/graphbuilder.h | 4 ++++ include/yaml-cpp/conversion.h | 6 ++++-- include/yaml-cpp/emitfromevents.h | 6 ++++-- include/yaml-cpp/emitter.h | 6 ++++-- include/yaml-cpp/emittermanip.h | 6 ++++-- include/yaml-cpp/eventhandler.h | 6 ++++-- include/yaml-cpp/exceptions.h | 6 ++++-- include/yaml-cpp/iterator.h | 6 ++++-- include/yaml-cpp/mark.h | 6 ++++-- include/yaml-cpp/node.h | 6 ++++-- include/yaml-cpp/nodeimpl.h | 6 ++++-- include/yaml-cpp/nodeproperties.h | 6 ++++-- include/yaml-cpp/nodereadimpl.h | 8 ++++++++ include/yaml-cpp/nodeutil.h | 6 ++++-- include/yaml-cpp/noncopyable.h | 6 ++++-- include/yaml-cpp/null.h | 6 ++++-- include/yaml-cpp/ostream.h | 6 ++++-- include/yaml-cpp/parser.h | 6 ++++-- include/yaml-cpp/stlemitter.h | 6 ++++-- include/yaml-cpp/stlnode.h | 6 ++++-- include/yaml-cpp/traits.h | 6 ++++-- include/yaml-cpp/yaml.h | 6 ++++-- src/aliascontent.h | 6 ++++-- src/collectionstack.h | 6 ++++-- src/content.h | 6 ++++-- src/contrib/graphbuilderadapter.h | 4 ++++ src/directives.h | 6 ++++-- src/emitterstate.h | 6 ++++-- src/emitterutils.h | 6 ++++-- src/exp.h | 6 ++++-- src/indentation.h | 6 ++++-- src/iterpriv.h | 6 ++++-- src/ltnode.h | 6 ++++-- src/map.h | 6 ++++-- src/nodebuilder.h | 6 ++++-- src/ptr_stack.h | 6 ++++-- src/regex.h | 6 ++++-- src/regeximpl.h | 6 ++++-- src/scalar.h | 6 ++++-- src/scanner.h | 6 ++++-- src/scanscalar.h | 6 ++++-- src/scantag.h | 6 ++++-- src/sequence.h | 6 ++++-- src/setting.h | 6 ++++-- src/singledocparser.h | 6 ++++-- src/stream.h | 6 ++++-- src/streamcharsource.h | 6 ++++-- src/stringsource.h | 6 ++++-- src/tag.h | 6 ++++-- src/token.h | 6 ++++-- test/emittertests.h | 6 ++++-- test/parsertests.h | 6 ++++-- test/spectests.h | 6 ++++-- test/tests.h | 6 ++++-- 57 files changed, 232 insertions(+), 108 deletions(-) diff --git a/include/yaml-cpp/aliasmanager.h b/include/yaml-cpp/aliasmanager.h index 4db9c89..8b01a69 100644 --- a/include/yaml-cpp/aliasmanager.h +++ b/include/yaml-cpp/aliasmanager.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef ALIASMANAGER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define ALIASMANAGER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "yaml-cpp/anchor.h" #include diff --git a/include/yaml-cpp/anchor.h b/include/yaml-cpp/anchor.h index c7b283a..175d4d7 100644 --- a/include/yaml-cpp/anchor.h +++ b/include/yaml-cpp/anchor.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include namespace YAML diff --git a/include/yaml-cpp/contrib/anchordict.h b/include/yaml-cpp/contrib/anchordict.h index fef8e9a..8638aab 100644 --- a/include/yaml-cpp/contrib/anchordict.h +++ b/include/yaml-cpp/contrib/anchordict.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include #include "../anchor.h" diff --git a/include/yaml-cpp/contrib/graphbuilder.h b/include/yaml-cpp/contrib/graphbuilder.h index 6b26b40..2ea139b 100644 --- a/include/yaml-cpp/contrib/graphbuilder.h +++ b/include/yaml-cpp/contrib/graphbuilder.h @@ -1,6 +1,10 @@ #ifndef GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include namespace YAML diff --git a/include/yaml-cpp/conversion.h b/include/yaml-cpp/conversion.h index fb2df7f..1036182 100644 --- a/include/yaml-cpp/conversion.h +++ b/include/yaml-cpp/conversion.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "yaml-cpp/null.h" #include "yaml-cpp/traits.h" diff --git a/include/yaml-cpp/emitfromevents.h b/include/yaml-cpp/emitfromevents.h index a50e590..6b4f8ff 100644 --- a/include/yaml-cpp/emitfromevents.h +++ b/include/yaml-cpp/emitfromevents.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "yaml-cpp/eventhandler.h" #include diff --git a/include/yaml-cpp/emitter.h b/include/yaml-cpp/emitter.h index c115dc2..ef362bb 100644 --- a/include/yaml-cpp/emitter.h +++ b/include/yaml-cpp/emitter.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "yaml-cpp/emittermanip.h" #include "yaml-cpp/ostream.h" diff --git a/include/yaml-cpp/emittermanip.h b/include/yaml-cpp/emittermanip.h index fc29655..28e88be 100644 --- a/include/yaml-cpp/emittermanip.h +++ b/include/yaml-cpp/emittermanip.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef EMITTERMANIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EMITTERMANIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include diff --git a/include/yaml-cpp/eventhandler.h b/include/yaml-cpp/eventhandler.h index f1f17db..bba874f 100644 --- a/include/yaml-cpp/eventhandler.h +++ b/include/yaml-cpp/eventhandler.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "yaml-cpp/anchor.h" #include diff --git a/include/yaml-cpp/exceptions.h b/include/yaml-cpp/exceptions.h index 402e284..e940499 100644 --- a/include/yaml-cpp/exceptions.h +++ b/include/yaml-cpp/exceptions.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "yaml-cpp/mark.h" #include "yaml-cpp/traits.h" diff --git a/include/yaml-cpp/iterator.h b/include/yaml-cpp/iterator.h index bb9141f..069e91d 100644 --- a/include/yaml-cpp/iterator.h +++ b/include/yaml-cpp/iterator.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + namespace YAML { diff --git a/include/yaml-cpp/mark.h b/include/yaml-cpp/mark.h index 7c3dfb3..358f251 100644 --- a/include/yaml-cpp/mark.h +++ b/include/yaml-cpp/mark.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef MARK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define MARK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + namespace YAML { diff --git a/include/yaml-cpp/node.h b/include/yaml-cpp/node.h index 6938504..993434f 100644 --- a/include/yaml-cpp/node.h +++ b/include/yaml-cpp/node.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "yaml-cpp/conversion.h" #include "yaml-cpp/exceptions.h" diff --git a/include/yaml-cpp/nodeimpl.h b/include/yaml-cpp/nodeimpl.h index e9755de..12b25b9 100644 --- a/include/yaml-cpp/nodeimpl.h +++ b/include/yaml-cpp/nodeimpl.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef NODEIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define NODEIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "yaml-cpp/nodeutil.h" diff --git a/include/yaml-cpp/nodeproperties.h b/include/yaml-cpp/nodeproperties.h index ae435d5..63be8b0 100644 --- a/include/yaml-cpp/nodeproperties.h +++ b/include/yaml-cpp/nodeproperties.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef NODEPROPERTIES_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define NODEPROPERTIES_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + namespace YAML { struct NodeProperties { diff --git a/include/yaml-cpp/nodereadimpl.h b/include/yaml-cpp/nodereadimpl.h index d315660..9ad5b83 100644 --- a/include/yaml-cpp/nodereadimpl.h +++ b/include/yaml-cpp/nodereadimpl.h @@ -1,4 +1,10 @@ +#ifndef NODEREADIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define NODEREADIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 #pragma once +#endif + namespace YAML { @@ -76,3 +82,5 @@ namespace YAML return Convert(scalar, value); } } + +#endif // NODEREADIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/nodeutil.h b/include/yaml-cpp/nodeutil.h index 1be6b69..98ea4fa 100644 --- a/include/yaml-cpp/nodeutil.h +++ b/include/yaml-cpp/nodeutil.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef NODEUTIL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define NODEUTIL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + namespace YAML { diff --git a/include/yaml-cpp/noncopyable.h b/include/yaml-cpp/noncopyable.h index 577b547..0b056e8 100644 --- a/include/yaml-cpp/noncopyable.h +++ b/include/yaml-cpp/noncopyable.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef NONCOPYABLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define NONCOPYABLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + namespace YAML { diff --git a/include/yaml-cpp/null.h b/include/yaml-cpp/null.h index 3857683..b430344 100644 --- a/include/yaml-cpp/null.h +++ b/include/yaml-cpp/null.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef NULL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define NULL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + namespace YAML { diff --git a/include/yaml-cpp/ostream.h b/include/yaml-cpp/ostream.h index a5912bb..90258ba 100644 --- a/include/yaml-cpp/ostream.h +++ b/include/yaml-cpp/ostream.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef OSTREAM_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define OSTREAM_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include diff --git a/include/yaml-cpp/parser.h b/include/yaml-cpp/parser.h index eec0e99..dc2ce5a 100644 --- a/include/yaml-cpp/parser.h +++ b/include/yaml-cpp/parser.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "yaml-cpp/noncopyable.h" #include diff --git a/include/yaml-cpp/stlemitter.h b/include/yaml-cpp/stlemitter.h index c2f86ff..1b5d864 100644 --- a/include/yaml-cpp/stlemitter.h +++ b/include/yaml-cpp/stlemitter.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef STLEMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define STLEMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include #include diff --git a/include/yaml-cpp/stlnode.h b/include/yaml-cpp/stlnode.h index cfe2f03..8d50f7f 100644 --- a/include/yaml-cpp/stlnode.h +++ b/include/yaml-cpp/stlnode.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef STLNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define STLNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include #include diff --git a/include/yaml-cpp/traits.h b/include/yaml-cpp/traits.h index e9c42ad..32a3155 100644 --- a/include/yaml-cpp/traits.h +++ b/include/yaml-cpp/traits.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + namespace YAML { diff --git a/include/yaml-cpp/yaml.h b/include/yaml-cpp/yaml.h index 052d306..674430e 100644 --- a/include/yaml-cpp/yaml.h +++ b/include/yaml-cpp/yaml.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "yaml-cpp/parser.h" #include "yaml-cpp/node.h" diff --git a/src/aliascontent.h b/src/aliascontent.h index d5893b4..235e88c 100644 --- a/src/aliascontent.h +++ b/src/aliascontent.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef ALIASCONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define ALIASCONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "content.h" diff --git a/src/collectionstack.h b/src/collectionstack.h index fd3b885..5274546 100644 --- a/src/collectionstack.h +++ b/src/collectionstack.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include #include diff --git a/src/content.h b/src/content.h index 598b290..f850247 100644 --- a/src/content.h +++ b/src/content.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef CONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define CONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "yaml-cpp/anchor.h" #include "yaml-cpp/exceptions.h" diff --git a/src/contrib/graphbuilderadapter.h b/src/contrib/graphbuilderadapter.h index 05a0b3a..b8c1f6a 100644 --- a/src/contrib/graphbuilderadapter.h +++ b/src/contrib/graphbuilderadapter.h @@ -1,6 +1,10 @@ #ifndef GRAPHBUILDERADAPTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define GRAPHBUILDERADAPTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include #include #include "yaml-cpp/eventhandler.h" diff --git a/src/directives.h b/src/directives.h index e063faa..2fa6f62 100644 --- a/src/directives.h +++ b/src/directives.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef DIRECTIVES_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define DIRECTIVES_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include #include diff --git a/src/emitterstate.h b/src/emitterstate.h index 87621b4..5df5008 100644 --- a/src/emitterstate.h +++ b/src/emitterstate.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef EMITTERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EMITTERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "setting.h" #include "yaml-cpp/emittermanip.h" diff --git a/src/emitterutils.h b/src/emitterutils.h index a44ae2c..5b3de82 100644 --- a/src/emitterutils.h +++ b/src/emitterutils.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef EMITTERUTILS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EMITTERUTILS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "yaml-cpp/ostream.h" #include diff --git a/src/exp.h b/src/exp.h index c42daec..0200d25 100644 --- a/src/exp.h +++ b/src/exp.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef EXP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EXP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "regex.h" #include diff --git a/src/indentation.h b/src/indentation.h index db382ef..89d68df 100644 --- a/src/indentation.h +++ b/src/indentation.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef INDENTATION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define INDENTATION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "yaml-cpp/ostream.h" #include diff --git a/src/iterpriv.h b/src/iterpriv.h index d091fbc..cade13f 100644 --- a/src/iterpriv.h +++ b/src/iterpriv.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef ITERPRIV_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define ITERPRIV_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "ltnode.h" #include diff --git a/src/ltnode.h b/src/ltnode.h index c1672de..cf85435 100644 --- a/src/ltnode.h +++ b/src/ltnode.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef LTNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define LTNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + namespace YAML { diff --git a/src/map.h b/src/map.h index 8eb44ee..ac2531b 100644 --- a/src/map.h +++ b/src/map.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef MAP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define MAP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "content.h" #include diff --git a/src/nodebuilder.h b/src/nodebuilder.h index 9ef6815..1ecf2e3 100644 --- a/src/nodebuilder.h +++ b/src/nodebuilder.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "yaml-cpp/eventhandler.h" #include "ptr_stack.h" #include diff --git a/src/ptr_stack.h b/src/ptr_stack.h index cac785b..7a3a51c 100644 --- a/src/ptr_stack.h +++ b/src/ptr_stack.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef PTR_STACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define PTR_STACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "yaml-cpp/noncopyable.h" #include #include diff --git a/src/regex.h b/src/regex.h index 12d9be7..d797e9a 100644 --- a/src/regex.h +++ b/src/regex.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef REGEX_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define REGEX_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include #include diff --git a/src/regeximpl.h b/src/regeximpl.h index c13f236..aad9708 100644 --- a/src/regeximpl.h +++ b/src/regeximpl.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef REGEXIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define REGEXIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "stream.h" #include "stringsource.h" diff --git a/src/scalar.h b/src/scalar.h index 5843470..0cca420 100644 --- a/src/scalar.h +++ b/src/scalar.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef SCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define SCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "content.h" #include diff --git a/src/scanner.h b/src/scanner.h index 17908cc..f76c172 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include #include diff --git a/src/scanscalar.h b/src/scanscalar.h index 1f92b9e..52123e7 100644 --- a/src/scanscalar.h +++ b/src/scanscalar.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef SCANSCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define SCANSCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include #include "regex.h" diff --git a/src/scantag.h b/src/scantag.h index 77b315d..869d9e8 100644 --- a/src/scantag.h +++ b/src/scantag.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef SCANTAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define SCANTAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include #include "stream.h" diff --git a/src/sequence.h b/src/sequence.h index 342c5cb..2078d19 100644 --- a/src/sequence.h +++ b/src/sequence.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef SEQUENCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define SEQUENCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "content.h" #include diff --git a/src/setting.h b/src/setting.h index f11142b..f503ad2 100644 --- a/src/setting.h +++ b/src/setting.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef SETTING_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define SETTING_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include #include diff --git a/src/singledocparser.h b/src/singledocparser.h index 28355b8..86688a6 100644 --- a/src/singledocparser.h +++ b/src/singledocparser.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef SINGLEDOCPARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define SINGLEDOCPARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "yaml-cpp/anchor.h" #include "yaml-cpp/noncopyable.h" diff --git a/src/stream.h b/src/stream.h index 7243fb6..e2fd4b5 100644 --- a/src/stream.h +++ b/src/stream.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef STREAM_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define STREAM_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "yaml-cpp/noncopyable.h" #include "yaml-cpp/mark.h" diff --git a/src/streamcharsource.h b/src/streamcharsource.h index 12548a4..55e9294 100644 --- a/src/streamcharsource.h +++ b/src/streamcharsource.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef STREAMCHARSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define STREAMCHARSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "yaml-cpp/noncopyable.h" #include diff --git a/src/stringsource.h b/src/stringsource.h index 20d56ae..8a45755 100644 --- a/src/stringsource.h +++ b/src/stringsource.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef STRINGSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define STRINGSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include diff --git a/src/tag.h b/src/tag.h index 68aa296..675b15e 100644 --- a/src/tag.h +++ b/src/tag.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef TAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define TAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include namespace YAML diff --git a/src/token.h b/src/token.h index 63093fc..11e97a3 100644 --- a/src/token.h +++ b/src/token.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef TOKEN_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define TOKEN_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include "yaml-cpp/mark.h" #include diff --git a/test/emittertests.h b/test/emittertests.h index e746e5a..4ba5f72 100644 --- a/test/emittertests.h +++ b/test/emittertests.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef EMITTERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EMITTERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + namespace Test { bool RunEmitterTests(); } diff --git a/test/parsertests.h b/test/parsertests.h index e63a2eb..a67fff8 100644 --- a/test/parsertests.h +++ b/test/parsertests.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef PARSERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define PARSERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + namespace Test { bool RunParserTests(); } diff --git a/test/spectests.h b/test/spectests.h index fcb1fb4..e8acfb7 100644 --- a/test/spectests.h +++ b/test/spectests.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef SPECTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define SPECTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + namespace Test { bool RunSpecTests(); } diff --git a/test/tests.h b/test/tests.h index 0d39007..ec466a4 100644 --- a/test/tests.h +++ b/test/tests.h @@ -1,8 +1,10 @@ -#pragma once - #ifndef TESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define TESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + #include namespace Test { From c6e085524a1f6577d08b316894ee536c94d700b1 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 2 Mar 2011 20:30:54 +0000 Subject: [PATCH 252/295] Included 'mark.h' in the graphbuilder so that its method for removing the unused param warning (casting to void) compiles on VS --- include/yaml-cpp/contrib/graphbuilder.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/yaml-cpp/contrib/graphbuilder.h b/include/yaml-cpp/contrib/graphbuilder.h index 2ea139b..f2237e3 100644 --- a/include/yaml-cpp/contrib/graphbuilder.h +++ b/include/yaml-cpp/contrib/graphbuilder.h @@ -5,11 +5,11 @@ #pragma once #endif +#include "yaml-cpp/mark.h" #include namespace YAML { - struct Mark; class Parser; // GraphBuilderInterface From 396e3309de2d2cf95114db019b4d758a957ac71c Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 2 Mar 2011 20:55:05 +0000 Subject: [PATCH 253/295] Refactored bool emitting to make it 1) correct for the short bool form and 2) not barf on early versions of VS --- include/yaml-cpp/emitter.h | 1 + src/emitter.cpp | 68 +++++++++++++++++++++++--------------- test/emittertests.cpp | 36 ++++++++++++++++++++ 3 files changed, 79 insertions(+), 26 deletions(-) diff --git a/include/yaml-cpp/emitter.h b/include/yaml-cpp/emitter.h index ef362bb..f7ec3e1 100644 --- a/include/yaml-cpp/emitter.h +++ b/include/yaml-cpp/emitter.h @@ -85,6 +85,7 @@ namespace YAML void EmitKindTag(); void EmitTag(bool verbatim, const _Tag& tag); + const char *ComputeFullBoolName(bool b) const; bool CanEmitNewline() const; private: diff --git a/src/emitter.cpp b/src/emitter.cpp index 03555ea..eb9c339 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -606,12 +606,45 @@ namespace YAML PostAtomicWrite(); } - namespace { - struct BoolName { std::string trueName, falseName; }; - struct BoolFormatNames { BoolName upper, lower, camel; }; - struct BoolTypes { BoolFormatNames yesNo, trueFalse, onOff; }; + const char *Emitter::ComputeFullBoolName(bool b) const + { + const EMITTER_MANIP mainFmt = (m_pState->GetBoolLengthFormat() == ShortBool ? YesNoBool : m_pState->GetBoolFormat()); + const EMITTER_MANIP caseFmt = m_pState->GetBoolCaseFormat(); + switch(mainFmt) { + case YesNoBool: + switch(caseFmt) { + case UpperCase: + return b ? "YES" : "NO"; + case CamelCase: + return b ? "Yes" : "No"; + case LowerCase: // fall through to default + default: + return b ? "yes" : "no"; + } + case OnOffBool: + switch(caseFmt) { + case UpperCase: + return b ? "ON" : "OFF"; + case CamelCase: + return b ? "On" : "Off"; + case LowerCase: // fall through to default + default: + return b ? "on" : "off"; + } + case TrueFalseBool: // fall through to default + default: + switch(caseFmt) { + case UpperCase: + return b ? "TRUE" : "FALSE"; + case CamelCase: + return b ? "True" : "False"; + case LowerCase: // fall through to default + default: + return b ? "true" : "false"; + } + } } - + Emitter& Emitter::Write(bool b) { if(!good()) @@ -619,30 +652,13 @@ namespace YAML PreAtomicWrite(); EmitSeparationIfNecessary(); - - // set up all possible bools to write - static const BoolTypes boolTypes = { - { { "YES", "NO" }, { "yes", "no" }, { "Yes", "No" } }, - { { "TRUE", "FALSE" }, { "true", "false" }, { "True", "False" } }, - { { "ON", "OFF" }, { "on", "off" }, { "On", "Off" } } - }; - - // select the right one - EMITTER_MANIP boolFmt = m_pState->GetBoolFormat(); - EMITTER_MANIP boolLengthFmt = m_pState->GetBoolLengthFormat(); - EMITTER_MANIP boolCaseFmt = m_pState->GetBoolCaseFormat(); - - const BoolFormatNames& fmtNames = (boolFmt == YesNoBool ? boolTypes.yesNo : boolFmt == TrueFalseBool ? boolTypes.trueFalse : boolTypes.onOff); - const BoolName& boolName = (boolCaseFmt == UpperCase ? fmtNames.upper : boolCaseFmt == LowerCase ? fmtNames.lower : fmtNames.camel); - const std::string& name = (b ? boolName.trueName : boolName.falseName); - - // and say it! - // TODO: should we disallow writing OnOffBool with ShortBool? (it'll just print "o" for both, which is silly) - if(boolLengthFmt == ShortBool) + + const char *name = ComputeFullBoolName(b); + if(m_pState->GetBoolLengthFormat() == ShortBool) m_stream << name[0]; else m_stream << name; - + PostAtomicWrite(); return *this; } diff --git a/test/emittertests.cpp b/test/emittertests.cpp index b81ab68..16f8764 100644 --- a/test/emittertests.cpp +++ b/test/emittertests.cpp @@ -741,6 +741,41 @@ namespace Test out << YAML::EndMap; desiredOutput = "---\napple: \":\"\nbanana: \":\""; } + + void BoolFormatting(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginSeq; + out << YAML::TrueFalseBool << YAML::UpperCase << true; + out << YAML::TrueFalseBool << YAML::CamelCase << true; + out << YAML::TrueFalseBool << YAML::LowerCase << true; + out << YAML::TrueFalseBool << YAML::UpperCase << false; + out << YAML::TrueFalseBool << YAML::CamelCase << false; + out << YAML::TrueFalseBool << YAML::LowerCase << false; + out << YAML::YesNoBool << YAML::UpperCase << true; + out << YAML::YesNoBool << YAML::CamelCase << true; + out << YAML::YesNoBool << YAML::LowerCase << true; + out << YAML::YesNoBool << YAML::UpperCase << false; + out << YAML::YesNoBool << YAML::CamelCase << false; + out << YAML::YesNoBool << YAML::LowerCase << false; + out << YAML::OnOffBool << YAML::UpperCase << true; + out << YAML::OnOffBool << YAML::CamelCase << true; + out << YAML::OnOffBool << YAML::LowerCase << true; + out << YAML::OnOffBool << YAML::UpperCase << false; + out << YAML::OnOffBool << YAML::CamelCase << false; + out << YAML::OnOffBool << YAML::LowerCase << false; + out << YAML::ShortBool << YAML::UpperCase << true; + out << YAML::ShortBool << YAML::CamelCase << true; + out << YAML::ShortBool << YAML::LowerCase << true; + out << YAML::ShortBool << YAML::UpperCase << false; + out << YAML::ShortBool << YAML::CamelCase << false; + out << YAML::ShortBool << YAML::LowerCase << false; + out << YAML::EndSeq; + desiredOutput = + "---\n- TRUE\n- True\n- true\n- FALSE\n- False\n- false\n" + "- YES\n- Yes\n- yes\n- NO\n- No\n- no\n" + "- ON\n- On\n- on\n- OFF\n- Off\n- off\n" + "- Y\n- Y\n- y\n- N\n- N\n- n"; + } //////////////////////////////////////////////////////////////////////////////////////////////////////// // incorrect emitting @@ -933,6 +968,7 @@ namespace Test RunEmitterTest(&Emitter::EmptyBinary, "empty binary", passed, total); RunEmitterTest(&Emitter::ColonAtEndOfScalar, "colon at end of scalar", passed, total); RunEmitterTest(&Emitter::ColonAsScalar, "colon as scalar", passed, total); + RunEmitterTest(&Emitter::BoolFormatting, "bool formatting", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total); From 152e48f0d06a2aa4e64ec37cf600b5fb98ca0448 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 2 Mar 2011 20:59:39 +0000 Subject: [PATCH 254/295] Prettied up the bool formatting code --- src/emitter.cpp | 42 +++++++++++++++++++----------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/emitter.cpp b/src/emitter.cpp index eb9c339..8dcc45c 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -613,36 +613,32 @@ namespace YAML switch(mainFmt) { case YesNoBool: switch(caseFmt) { - case UpperCase: - return b ? "YES" : "NO"; - case CamelCase: - return b ? "Yes" : "No"; - case LowerCase: // fall through to default - default: - return b ? "yes" : "no"; + case UpperCase: return b ? "YES" : "NO"; + case CamelCase: return b ? "Yes" : "No"; + case LowerCase: return b ? "yes" : "no"; + default: break; } + break; case OnOffBool: switch(caseFmt) { - case UpperCase: - return b ? "ON" : "OFF"; - case CamelCase: - return b ? "On" : "Off"; - case LowerCase: // fall through to default - default: - return b ? "on" : "off"; + case UpperCase: return b ? "ON" : "OFF"; + case CamelCase: return b ? "On" : "Off"; + case LowerCase: return b ? "on" : "off"; + default: break; } - case TrueFalseBool: // fall through to default - default: + break; + case TrueFalseBool: switch(caseFmt) { - case UpperCase: - return b ? "TRUE" : "FALSE"; - case CamelCase: - return b ? "True" : "False"; - case LowerCase: // fall through to default - default: - return b ? "true" : "false"; + case UpperCase: return b ? "TRUE" : "FALSE"; + case CamelCase: return b ? "True" : "False"; + case LowerCase: return b ? "true" : "false"; + default: break; } + break; + default: + break; } + return b ? "y" : "n"; // should never get here, but it can't hurt to give these answers } Emitter& Emitter::Write(bool b) From f1f983764fdf48ac4a7dd61cde42151032bd5944 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 2 Mar 2011 21:03:03 +0000 Subject: [PATCH 255/295] Removed the old, unsupported Visual Studio files (just build with CMake) --- parse.vcproj | 194 -------------------- test.vcproj | 226 ----------------------- yamlcpp.sln | 38 ---- yamlcpp.vcproj | 487 ------------------------------------------------- 4 files changed, 945 deletions(-) delete mode 100644 parse.vcproj delete mode 100644 test.vcproj delete mode 100644 yamlcpp.sln delete mode 100644 yamlcpp.vcproj diff --git a/parse.vcproj b/parse.vcproj deleted file mode 100644 index 3bca65d..0000000 --- a/parse.vcproj +++ /dev/null @@ -1,194 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test.vcproj b/test.vcproj deleted file mode 100644 index 137cfa6..0000000 --- a/test.vcproj +++ /dev/null @@ -1,226 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/yamlcpp.sln b/yamlcpp.sln deleted file mode 100644 index 44da0ab..0000000 --- a/yamlcpp.sln +++ /dev/null @@ -1,38 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yamlcpp", "yamlcpp.vcproj", "{3104AB4E-CD31-4F47-95E9-0E8D9374E15D}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcproj", "{D1108F40-6ADF-467E-A95A-236C39A515C5}" - ProjectSection(ProjectDependencies) = postProject - {3104AB4E-CD31-4F47-95E9-0E8D9374E15D} = {3104AB4E-CD31-4F47-95E9-0E8D9374E15D} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "parse", "parse.vcproj", "{CD007B57-7812-4930-A5E2-6E5E56338814}" - ProjectSection(ProjectDependencies) = postProject - {3104AB4E-CD31-4F47-95E9-0E8D9374E15D} = {3104AB4E-CD31-4F47-95E9-0E8D9374E15D} - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Win32 = Debug|Win32 - Release|Win32 = Release|Win32 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Debug|Win32.ActiveCfg = Debug|Win32 - {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Debug|Win32.Build.0 = Debug|Win32 - {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Release|Win32.ActiveCfg = Release|Win32 - {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Release|Win32.Build.0 = Release|Win32 - {D1108F40-6ADF-467E-A95A-236C39A515C5}.Debug|Win32.ActiveCfg = Debug|Win32 - {D1108F40-6ADF-467E-A95A-236C39A515C5}.Debug|Win32.Build.0 = Debug|Win32 - {D1108F40-6ADF-467E-A95A-236C39A515C5}.Release|Win32.ActiveCfg = Release|Win32 - {D1108F40-6ADF-467E-A95A-236C39A515C5}.Release|Win32.Build.0 = Release|Win32 - {CD007B57-7812-4930-A5E2-6E5E56338814}.Debug|Win32.ActiveCfg = Debug|Win32 - {CD007B57-7812-4930-A5E2-6E5E56338814}.Debug|Win32.Build.0 = Debug|Win32 - {CD007B57-7812-4930-A5E2-6E5E56338814}.Release|Win32.ActiveCfg = Release|Win32 - {CD007B57-7812-4930-A5E2-6E5E56338814}.Release|Win32.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/yamlcpp.vcproj b/yamlcpp.vcproj deleted file mode 100644 index 6239819..0000000 --- a/yamlcpp.vcproj +++ /dev/null @@ -1,487 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From e6c100704341e0f77186606d6ecc6c7838e76f80 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 2 Mar 2011 21:09:38 +0000 Subject: [PATCH 256/295] Tiny formatting change in CMake file --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7807494..639af91 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -109,12 +109,13 @@ if(CMAKE_COMPILER_IS_GNUCXX) if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() - set(GCC_EXTRA_OPTIONS "") # set(CMAKE_CXX_FLAGS_RELEASE "-O2") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") set(CMAKE_CXX_FLAGS_DEBUG "-g") # + set(GCC_EXTRA_OPTIONS "") + # set(FLAG_TESTED "-Wextra") check_cxx_compiler_flag(${FLAG_TESTED} FLAG_WEXTRA) if(FLAG_WEXTRA) From 6f7995d27e615df9cd08fdc7a5fd88c6b223e2b0 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 3 Mar 2011 00:19:26 +0000 Subject: [PATCH 257/295] Merged r444:449 from the node refactoring branch to the trunk --- include/yaml-cpp/aliasmanager.h | 6 - include/yaml-cpp/contrib/graphbuilder.h | 6 +- include/yaml-cpp/emitfromevents.h | 2 +- include/yaml-cpp/eventhandler.h | 2 +- include/yaml-cpp/iterator.h | 5 +- {src => include/yaml-cpp}/ltnode.h | 0 include/yaml-cpp/node.h | 55 +++-- include/yaml-cpp/nodeimpl.h | 27 ++- include/yaml-cpp/nodeproperties.h | 16 -- src/aliascontent.cpp | 83 ------- src/aliascontent.h | 41 ---- src/aliasmanager.cpp | 20 +- src/content.cpp | 21 -- src/content.h | 62 ------ src/contrib/graphbuilderadapter.cpp | 4 +- src/contrib/graphbuilderadapter.h | 2 +- src/emitfromevents.cpp | 7 +- src/iterator.cpp | 18 +- src/iterpriv.h | 2 +- src/map.cpp | 91 -------- src/map.h | 48 ---- src/node.cpp | 280 +++++++++++++----------- src/nodebuilder.cpp | 61 +++--- src/nodebuilder.h | 14 +- src/nodeownership.cpp | 31 +++ src/nodeownership.h | 39 ++++ src/ptr_vector.h | 45 ++++ src/scalar.cpp | 34 --- src/scalar.h | 43 ---- src/sequence.cpp | 83 ------- src/sequence.h | 45 ---- src/singledocparser.cpp | 22 +- test/parsertests.cpp | 6 +- test/spectests.cpp | 58 ++--- util/parse.cpp | 2 +- 35 files changed, 421 insertions(+), 860 deletions(-) rename {src => include/yaml-cpp}/ltnode.h (100%) delete mode 100644 include/yaml-cpp/nodeproperties.h delete mode 100644 src/aliascontent.cpp delete mode 100644 src/aliascontent.h delete mode 100644 src/content.cpp delete mode 100644 src/content.h delete mode 100644 src/map.cpp delete mode 100644 src/map.h create mode 100644 src/nodeownership.cpp create mode 100644 src/nodeownership.h create mode 100644 src/ptr_vector.h delete mode 100644 src/scalar.cpp delete mode 100644 src/scalar.h delete mode 100644 src/sequence.cpp delete mode 100644 src/sequence.h diff --git a/include/yaml-cpp/aliasmanager.h b/include/yaml-cpp/aliasmanager.h index 8b01a69..d650269 100644 --- a/include/yaml-cpp/aliasmanager.h +++ b/include/yaml-cpp/aliasmanager.h @@ -18,18 +18,12 @@ namespace YAML 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 NodeByNode; - NodeByNode m_newIdentityByOldIdentity; - typedef std::map AnchorByIdentity; AnchorByIdentity m_anchorByIdentity; diff --git a/include/yaml-cpp/contrib/graphbuilder.h b/include/yaml-cpp/contrib/graphbuilder.h index f2237e3..7c09fb2 100644 --- a/include/yaml-cpp/contrib/graphbuilder.h +++ b/include/yaml-cpp/contrib/graphbuilder.h @@ -20,7 +20,7 @@ namespace YAML { public: // Create and return a new node with a null value. - virtual void *NewNull(const std::string& tag, void *pParentNode) = 0; + virtual void *NewNull(const Mark& mark, 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; @@ -74,8 +74,8 @@ namespace YAML GraphBuilderInterface& AsBuilderInterface() {return *this;} - virtual void *NewNull(const std::string& tag, void* pParentNode) { - return CheckType(m_impl.NewNull(tag, AsNode(pParentNode))); + virtual void *NewNull(const Mark& mark, void* pParentNode) { + return CheckType(m_impl.NewNull(mark, AsNode(pParentNode))); } virtual void *NewScalar(const Mark& mark, const std::string& tag, void *pParentNode, const std::string& value) { diff --git a/include/yaml-cpp/emitfromevents.h b/include/yaml-cpp/emitfromevents.h index 6b4f8ff..4f9badc 100644 --- a/include/yaml-cpp/emitfromevents.h +++ b/include/yaml-cpp/emitfromevents.h @@ -20,7 +20,7 @@ namespace YAML virtual void OnDocumentStart(const Mark& mark); virtual void OnDocumentEnd(); - virtual void OnNull(const std::string& tag, anchor_t anchor); + virtual void OnNull(const Mark& mark, 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); diff --git a/include/yaml-cpp/eventhandler.h b/include/yaml-cpp/eventhandler.h index bba874f..80afdb4 100644 --- a/include/yaml-cpp/eventhandler.h +++ b/include/yaml-cpp/eventhandler.h @@ -20,7 +20,7 @@ namespace YAML virtual void OnDocumentStart(const Mark& mark) = 0; virtual void OnDocumentEnd() = 0; - virtual void OnNull(const std::string& tag, anchor_t anchor) = 0; + virtual void OnNull(const Mark& mark, 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; diff --git a/include/yaml-cpp/iterator.h b/include/yaml-cpp/iterator.h index 069e91d..e1d95e4 100644 --- a/include/yaml-cpp/iterator.h +++ b/include/yaml-cpp/iterator.h @@ -5,6 +5,7 @@ #pragma once #endif +#include namespace YAML { @@ -15,7 +16,7 @@ namespace YAML { public: Iterator(); - Iterator(IterPriv *pData); + Iterator(std::auto_ptr pData); Iterator(const Iterator& rhs); ~Iterator(); @@ -31,7 +32,7 @@ namespace YAML friend bool operator != (const Iterator& it, const Iterator& jt); private: - IterPriv *m_pData; + std::auto_ptr m_pData; }; } diff --git a/src/ltnode.h b/include/yaml-cpp/ltnode.h similarity index 100% rename from src/ltnode.h rename to include/yaml-cpp/ltnode.h diff --git a/include/yaml-cpp/node.h b/include/yaml-cpp/node.h index 993434f..c0fa379 100644 --- a/include/yaml-cpp/node.h +++ b/include/yaml-cpp/node.h @@ -9,28 +9,32 @@ #include "yaml-cpp/conversion.h" #include "yaml-cpp/exceptions.h" #include "yaml-cpp/iterator.h" +#include "yaml-cpp/ltnode.h" #include "yaml-cpp/mark.h" #include "yaml-cpp/noncopyable.h" #include -#include -#include #include #include +#include +#include namespace YAML { class AliasManager; class Content; + class NodeOwnership; class Scanner; class Emitter; class EventHandler; - struct NodeProperties; - enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP }; + struct NodeType { enum value { Null, Scalar, Sequence, Map }; }; class Node: private noncopyable { public: + friend class NodeOwnership; + friend class NodeBuilder; + Node(); ~Node(); @@ -38,16 +42,9 @@ namespace YAML std::auto_ptr Clone() const; 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 pNode); - void Insert(std::auto_ptr pKey, std::auto_ptr pValue); - - CONTENT_TYPE GetType() const { return m_type; } + NodeType::value Type() const { return m_type; } + bool IsAliased() const; // file location of start of this node const Mark GetMark() const { return m_mark; } @@ -84,13 +81,8 @@ namespace YAML const Node *FindValue(const char *key) const; const Node& operator [] (const char *key) const; - // for anchors/aliases - const Node *Identity() const { return m_pIdentity; } - bool IsAlias() const { return m_alias; } - bool IsReferenced() const { return m_referenced; } - // for tags - const std::string GetTag() const { return IsAlias() ? m_pIdentity->GetTag() : m_tag; } + const std::string& Tag() const { return m_tag; } // emitting friend Emitter& operator << (Emitter& out, const Node& node); @@ -100,6 +92,16 @@ namespace YAML friend bool operator < (const Node& n1, const Node& n2); private: + explicit Node(NodeOwnership& owner); + Node& CreateNode(); + + void Init(NodeType::value type, const Mark& mark, const std::string& tag); + + void MarkAsAliased(); + void SetScalarData(const std::string& data); + void Append(Node& node); + void Insert(Node& key, Node& value); + // helper for sequences template friend struct _FindFromNodeAtIndex; const Node *FindAtIndex(std::size_t i) const; @@ -112,13 +114,18 @@ namespace YAML const Node *FindValueForKey(const T& key) const; private: + std::auto_ptr m_pOwnership; + Mark m_mark; std::string m_tag; - CONTENT_TYPE m_type; - Content *m_pContent; - bool m_alias; - const Node *m_pIdentity; - mutable bool m_referenced; + + typedef std::vector node_seq; + typedef std::map node_map; + + NodeType::value m_type; + std::string m_scalarData; + node_seq m_seqData; + node_map m_mapData; }; // comparisons with auto-conversion diff --git a/include/yaml-cpp/nodeimpl.h b/include/yaml-cpp/nodeimpl.h index 12b25b9..21dc276 100644 --- a/include/yaml-cpp/nodeimpl.h +++ b/include/yaml-cpp/nodeimpl.h @@ -7,6 +7,7 @@ #include "yaml-cpp/nodeutil.h" +#include namespace YAML { @@ -31,14 +32,17 @@ namespace YAML template inline const Node *Node::FindValue(const T& key) const { - switch(GetType()) { - case CT_MAP: - return FindValueForKey(key); - case CT_SEQUENCE: + switch(m_type) { + case NodeType::Null: + case NodeType::Scalar: + throw BadDereference(); + case NodeType::Sequence: return FindFromNodeAtIndex(*this, key); - default: - return 0; + case NodeType::Map: + return FindValueForKey(key); } + assert(false); + throw BadDereference(); } template @@ -56,14 +60,9 @@ namespace YAML template inline const Node& Node::GetValue(const T& key) const { - if(!m_pContent) - throw BadDereference(); - - const Node *pValue = FindValue(key); - if(!pValue) - throw MakeTypedKeyNotFound(m_mark, key); - - return *pValue; + if(const Node *pValue = FindValue(key)) + return *pValue; + throw MakeTypedKeyNotFound(m_mark, key); } template diff --git a/include/yaml-cpp/nodeproperties.h b/include/yaml-cpp/nodeproperties.h deleted file mode 100644 index 63be8b0..0000000 --- a/include/yaml-cpp/nodeproperties.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef NODEPROPERTIES_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#define NODEPROPERTIES_H_62B23520_7C8E_11DE_8A39_0800200C9A66 - -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 -#pragma once -#endif - -namespace YAML -{ - struct NodeProperties { - std::string tag; - std::string anchor; - }; -} - -#endif // NODEPROPERTIES_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/aliascontent.cpp b/src/aliascontent.cpp deleted file mode 100644 index e59d5ad..0000000 --- a/src/aliascontent.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "aliascontent.h" - -namespace YAML -{ - AliasContent::AliasContent(Content* pNodeContent): m_pRef(pNodeContent) - { - } - - bool AliasContent::GetBegin(std::vector ::const_iterator& i) const - { - return m_pRef->GetBegin(i); - } - - bool AliasContent::GetBegin(std::map ::const_iterator& i) const - { - return m_pRef->GetBegin(i); - } - - bool AliasContent::GetEnd(std::vector ::const_iterator& i) const - { - return m_pRef->GetEnd(i); - } - - bool AliasContent::GetEnd(std::map ::const_iterator& i) const - { - return m_pRef->GetEnd(i); - } - - Node* AliasContent::GetNode(std::size_t n) const - { - return m_pRef->GetNode(n); - } - - std::size_t AliasContent::GetSize() const - { - return m_pRef->GetSize(); - } - - bool AliasContent::IsScalar() const - { - return m_pRef->IsScalar(); - } - - bool AliasContent::IsMap() const - { - return m_pRef->IsMap(); - } - - bool AliasContent::IsSequence() const - { - return m_pRef->IsSequence(); - } - - bool AliasContent::GetScalar(std::string& scalar) const - { - 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); - } - - int AliasContent::Compare(Scalar *pScalar) - { - return m_pRef->Compare(pScalar); - } - - int AliasContent::Compare(Sequence *pSequence) - { - return m_pRef->Compare(pSequence); - } - - int AliasContent::Compare(Map *pMap) - { - return m_pRef->Compare(pMap); - } -} diff --git a/src/aliascontent.h b/src/aliascontent.h deleted file mode 100644 index 235e88c..0000000 --- a/src/aliascontent.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef ALIASCONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#define ALIASCONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 - -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 -#pragma once -#endif - - -#include "content.h" - -namespace YAML -{ - class AliasContent : public Content - { - public: - AliasContent(Content *pNodeContent); - - virtual bool GetBegin(std::vector ::const_iterator&) const; - virtual bool GetBegin(std::map ::const_iterator&) const; - virtual bool GetEnd(std::vector ::const_iterator&) const; - virtual bool GetEnd(std::map ::const_iterator&) const; - virtual Node* GetNode(std::size_t) const; - virtual std::size_t GetSize() const; - virtual bool IsScalar() const; - virtual bool IsMap() const; - 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 *); - virtual int Compare(Sequence *); - virtual int Compare(Map *); - - private: - Content* m_pRef; - }; -} - -#endif // ALIASCONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/aliasmanager.cpp b/src/aliasmanager.cpp index 89dfd03..ed4d3b5 100644 --- a/src/aliasmanager.cpp +++ b/src/aliasmanager.cpp @@ -11,33 +11,17 @@ namespace YAML 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; diff --git a/src/content.cpp b/src/content.cpp deleted file mode 100644 index a1540d1..0000000 --- a/src/content.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "content.h" -#include "yaml-cpp/node.h" -#include - -namespace YAML -{ - void Content::SetData(const std::string&) - { - assert(false); // TODO: throw - } - - void Content::Append(std::auto_ptr) - { - assert(false); // TODO: throw - } - - void Content::Insert(std::auto_ptr, std::auto_ptr) - { - assert(false); // TODO: throw - } -} diff --git a/src/content.h b/src/content.h deleted file mode 100644 index f850247..0000000 --- a/src/content.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef CONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#define CONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 - -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 -#pragma once -#endif - - -#include "yaml-cpp/anchor.h" -#include "yaml-cpp/exceptions.h" -#include "ltnode.h" -#include -#include -#include - -namespace YAML -{ - struct Mark; - struct NodeProperties; - class AliasManager; - class EventHandler; - class Map; - class Node; - class Scalar; - class Scanner; - class Sequence; - - class Content - { - public: - Content() {} - virtual ~Content() {} - - virtual bool GetBegin(std::vector ::const_iterator&) const { return false; } - virtual bool GetBegin(std::map ::const_iterator&) const { return false; } - virtual bool GetEnd(std::vector ::const_iterator&) const { return false; } - virtual bool GetEnd(std::map ::const_iterator&) const { return false; } - virtual Node *GetNode(std::size_t) const { return 0; } - virtual std::size_t GetSize() const { return 0; } - 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 pNode); - virtual void Insert(std::auto_ptr pKey, std::auto_ptr 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; } - - // ordering - virtual int Compare(Content *) { return 0; } - virtual int Compare(Scalar *) { return 0; } - virtual int Compare(Sequence *) { return 0; } - virtual int Compare(Map *) { return 0; } - - protected: - }; -} - -#endif // CONTENT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/contrib/graphbuilderadapter.cpp b/src/contrib/graphbuilderadapter.cpp index 6431a45..557e97c 100644 --- a/src/contrib/graphbuilderadapter.cpp +++ b/src/contrib/graphbuilderadapter.cpp @@ -4,10 +4,10 @@ namespace YAML { int GraphBuilderAdapter::ContainerFrame::sequenceMarker; - void GraphBuilderAdapter::OnNull(const std::string& tag, anchor_t anchor) + void GraphBuilderAdapter::OnNull(const Mark& mark, anchor_t anchor) { void *pParent = GetCurrentParent(); - void *pNode = m_builder.NewNull(tag, pParent); + void *pNode = m_builder.NewNull(mark, pParent); RegisterAnchor(anchor, pNode); DispositionNode(pNode); diff --git a/src/contrib/graphbuilderadapter.h b/src/contrib/graphbuilderadapter.h index b8c1f6a..8e5cc07 100644 --- a/src/contrib/graphbuilderadapter.h +++ b/src/contrib/graphbuilderadapter.h @@ -24,7 +24,7 @@ namespace YAML virtual void OnDocumentStart(const Mark& mark) {(void)mark;} virtual void OnDocumentEnd() {} - virtual void OnNull(const std::string& tag, anchor_t anchor); + virtual void OnNull(const Mark& mark, 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); diff --git a/src/emitfromevents.cpp b/src/emitfromevents.cpp index 4105a18..49fc10b 100644 --- a/src/emitfromevents.cpp +++ b/src/emitfromevents.cpp @@ -26,12 +26,11 @@ namespace YAML { } - void EmitFromEvents::OnNull(const std::string& tag, anchor_t anchor) + void EmitFromEvents::OnNull(const Mark&, anchor_t anchor) { BeginNode(); - EmitProps(tag, anchor); - if(tag.empty()) - m_emitter << Null; + EmitProps("", anchor); + m_emitter << Null; } void EmitFromEvents::OnAlias(const Mark&, anchor_t anchor) diff --git a/src/iterator.cpp b/src/iterator.cpp index 2b7742b..f4159e3 100644 --- a/src/iterator.cpp +++ b/src/iterator.cpp @@ -4,18 +4,16 @@ namespace YAML { - Iterator::Iterator(): m_pData(0) - { - m_pData = new IterPriv; - } - - Iterator::Iterator(IterPriv *pData): m_pData(pData) + Iterator::Iterator(): m_pData(new IterPriv) { } - Iterator::Iterator(const Iterator& rhs): m_pData(0) + Iterator::Iterator(std::auto_ptr pData): m_pData(pData) + { + } + + Iterator::Iterator(const Iterator& rhs): m_pData(new IterPriv(*rhs.m_pData)) { - m_pData = new IterPriv(*rhs.m_pData); } Iterator& Iterator::operator = (const Iterator& rhs) @@ -23,14 +21,12 @@ namespace YAML if(this == &rhs) return *this; - delete m_pData; - m_pData = new IterPriv(*rhs.m_pData); + m_pData.reset(new IterPriv(*rhs.m_pData)); return *this; } Iterator::~Iterator() { - delete m_pData; } Iterator& Iterator::operator ++ () diff --git a/src/iterpriv.h b/src/iterpriv.h index cade13f..8e2ab22 100644 --- a/src/iterpriv.h +++ b/src/iterpriv.h @@ -6,7 +6,7 @@ #endif -#include "ltnode.h" +#include "yaml-cpp/ltnode.h" #include #include diff --git a/src/map.cpp b/src/map.cpp deleted file mode 100644 index 902b256..0000000 --- a/src/map.cpp +++ /dev/null @@ -1,91 +0,0 @@ -#include "map.h" -#include "yaml-cpp/node.h" -#include "yaml-cpp/eventhandler.h" -#include "yaml-cpp/exceptions.h" - -namespace YAML -{ - Map::Map() - { - } - - Map::~Map() - { - Clear(); - } - - void Map::Clear() - { - for(node_map::const_iterator it=m_data.begin();it!=m_data.end();++it) { - delete it->first; - delete it->second; - } - m_data.clear(); - } - - bool Map::GetBegin(std::map ::const_iterator& it) const - { - it = m_data.begin(); - return true; - } - - bool Map::GetEnd(std::map ::const_iterator& it) const - { - it = m_data.end(); - return true; - } - - std::size_t Map::GetSize() const - { - return m_data.size(); - } - - void Map::Insert(std::auto_ptr pKey, std::auto_ptr pValue) - { - node_map::const_iterator it = m_data.find(pKey.get()); - if(it != m_data.end()) - return; - - m_data[pKey.release()] = pValue.release(); - } - - void Map::EmitEvents(AliasManager& am, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const - { - 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) - { - return -pContent->Compare(this); - } - - int Map::Compare(Map *pMap) - { - node_map::const_iterator it = m_data.begin(), jt = pMap->m_data.begin(); - while(1) { - if(it == m_data.end()) { - if(jt == pMap->m_data.end()) - return 0; - else - return -1; - } - if(jt == pMap->m_data.end()) - return 1; - - int cmp = it->first->Compare(*jt->first); - if(cmp != 0) - return cmp; - - cmp = it->second->Compare(*jt->second); - if(cmp != 0) - return cmp; - } - - return 0; - } -} diff --git a/src/map.h b/src/map.h deleted file mode 100644 index ac2531b..0000000 --- a/src/map.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef MAP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#define MAP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 - -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 -#pragma once -#endif - - -#include "content.h" -#include -#include - -namespace YAML -{ - class Node; - - class Map: public Content - { - private: - typedef std::map node_map; - - public: - Map(); - virtual ~Map(); - - void Clear(); - - virtual bool GetBegin(std::map ::const_iterator& it) const; - virtual bool GetEnd(std::map ::const_iterator& it) const; - virtual std::size_t GetSize() const; - - virtual void Insert(std::auto_ptr pKey, std::auto_ptr 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; } - - // ordering - virtual int Compare(Content *pContent); - virtual int Compare(Scalar *) { return 1; } - virtual int Compare(Sequence *) { return 1; } - virtual int Compare(Map *pMap); - - private: - node_map m_data; - }; -} - -#endif // MAP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/node.cpp b/src/node.cpp index a17eefa..c9a8000 100644 --- a/src/node.cpp +++ b/src/node.cpp @@ -1,33 +1,29 @@ #include "yaml-cpp/node.h" -#include "aliascontent.h" +#include "iterpriv.h" +#include "nodebuilder.h" +#include "nodeownership.h" +#include "scanner.h" +#include "tag.h" +#include "token.h" #include "yaml-cpp/aliasmanager.h" -#include "content.h" #include "yaml-cpp/emitfromevents.h" #include "yaml-cpp/emitter.h" #include "yaml-cpp/eventhandler.h" -#include "iterpriv.h" -#include "map.h" -#include "nodebuilder.h" -#include "yaml-cpp/nodeproperties.h" -#include "scalar.h" -#include "scanner.h" -#include "sequence.h" -#include "tag.h" -#include "token.h" #include #include namespace YAML { - // the ordering! - bool ltnode::operator ()(const Node *pNode1, const Node *pNode2) const - { + bool ltnode::operator()(const Node *pNode1, const Node *pNode2) const { return *pNode1 < *pNode2; } - Node::Node(): m_type(CT_NONE), m_pContent(0), m_alias(false), m_referenced(false) + Node::Node(): m_pOwnership(new NodeOwnership), m_type(NodeType::Null) + { + } + + Node::Node(NodeOwnership& owner): m_pOwnership(new NodeOwnership(&owner)), m_type(NodeType::Null) { - m_pIdentity = this; } Node::~Node() @@ -37,14 +33,24 @@ namespace YAML void Node::Clear() { - delete m_pContent; - m_type = CT_NONE; - m_pContent = 0; - m_alias = false; - m_referenced = false; + m_pOwnership.reset(new NodeOwnership); + m_type = NodeType::Null; m_tag.clear(); + m_scalarData.clear(); + m_seqData.clear(); + m_mapData.clear(); } + bool Node::IsAliased() const + { + return m_pOwnership->IsAliased(*this); + } + + Node& Node::CreateNode() + { + return m_pOwnership->Create(); + } + std::auto_ptr Node::Clone() const { std::auto_ptr pNode(new Node); @@ -64,9 +70,10 @@ namespace YAML 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)); + if(IsAliased()) { + anchor = am.LookupAnchor(*this); + if(anchor) { + eventHandler.OnAlias(m_mark, anchor); return; } @@ -74,93 +81,76 @@ namespace YAML anchor = am.LookupAnchor(*this); } - if(m_pContent) - m_pContent->EmitEvents(am, eventHandler, m_mark, GetTag(), anchor); - else - eventHandler.OnNull(GetTag(), anchor); + switch(m_type) { + case NodeType::Null: + eventHandler.OnNull(m_mark, anchor); + break; + case NodeType::Scalar: + eventHandler.OnScalar(m_mark, m_tag, anchor, m_scalarData); + break; + case NodeType::Sequence: + eventHandler.OnSequenceStart(m_mark, m_tag, anchor); + for(std::size_t i=0;iEmitEvents(am, eventHandler); + eventHandler.OnSequenceEnd(); + break; + case NodeType::Map: + eventHandler.OnMapStart(m_mark, m_tag, anchor); + for(node_map::const_iterator it=m_mapData.begin();it!=m_mapData.end();++it) { + it->first->EmitEvents(am, eventHandler); + it->second->EmitEvents(am, eventHandler); + } + eventHandler.OnMapEnd(); + break; + } } - void Node::Init(CONTENT_TYPE type, const Mark& mark, const std::string& tag) + void Node::Init(NodeType::value type, const Mark& mark, const std::string& tag) { 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; - break; - case CT_SEQUENCE: - m_pContent = new Sequence; - break; - case CT_MAP: - m_pContent = new Map; - break; - default: - m_pContent = 0; - break; - } } - void Node::InitNull(const std::string& tag) + void Node::MarkAsAliased() { - Clear(); - m_tag = tag; - m_alias = false; - m_pIdentity = this; - m_referenced = false; - } - - void Node::InitAlias(const Mark& mark, const Node& identity) - { - Clear(); - m_mark = mark; - m_alias = true; - m_pIdentity = &identity; - if(identity.m_pContent) { - m_pContent = new AliasContent(identity.m_pContent); - m_type = identity.GetType(); - } - identity.m_referenced = true; - } - - void Node::SetData(const std::string& data) - { - assert(m_pContent); // TODO: throw - m_pContent->SetData(data); - } - - void Node::Append(std::auto_ptr pNode) - { - assert(m_pContent); // TODO: throw - m_pContent->Append(pNode); + m_pOwnership->MarkAsAliased(*this); } - void Node::Insert(std::auto_ptr pKey, std::auto_ptr pValue) + void Node::SetScalarData(const std::string& data) { - assert(m_pContent); // TODO: throw - m_pContent->Insert(pKey, pValue); + assert(m_type == NodeType::Scalar); // TODO: throw? + m_scalarData = data; + } + + void Node::Append(Node& node) + { + assert(m_type == NodeType::Sequence); // TODO: throw? + m_seqData.push_back(&node); + } + + void Node::Insert(Node& key, Node& value) + { + assert(m_type == NodeType::Map); // TODO: throw? + m_mapData[&key] = &value; } // begin // Returns an iterator to the beginning of this (sequence or map). Iterator Node::begin() const { - if(!m_pContent) - return Iterator(); - - std::vector ::const_iterator seqIter; - if(m_pContent->GetBegin(seqIter)) - return Iterator(new IterPriv(seqIter)); - - std::map ::const_iterator mapIter; - if(m_pContent->GetBegin(mapIter)) - return Iterator(new IterPriv(mapIter)); - + switch(m_type) { + case NodeType::Null: + case NodeType::Scalar: + return Iterator(); + case NodeType::Sequence: + return Iterator(std::auto_ptr(new IterPriv(m_seqData.begin()))); + case NodeType::Map: + return Iterator(std::auto_ptr(new IterPriv(m_mapData.begin()))); + } + + assert(false); return Iterator(); } @@ -168,50 +158,62 @@ namespace YAML // . Returns an iterator to the end of this (sequence or map). Iterator Node::end() const { - if(!m_pContent) - return Iterator(); - - std::vector ::const_iterator seqIter; - if(m_pContent->GetEnd(seqIter)) - return Iterator(new IterPriv(seqIter)); - - std::map ::const_iterator mapIter; - if(m_pContent->GetEnd(mapIter)) - return Iterator(new IterPriv(mapIter)); - + switch(m_type) { + case NodeType::Null: + case NodeType::Scalar: + return Iterator(); + case NodeType::Sequence: + return Iterator(std::auto_ptr(new IterPriv(m_seqData.end()))); + case NodeType::Map: + return Iterator(std::auto_ptr(new IterPriv(m_mapData.end()))); + } + + assert(false); return Iterator(); } // size - // . Returns the size of this node, if it's a sequence node. + // . Returns the size of a sequence or map node // . Otherwise, returns zero. std::size_t Node::size() const { - if(!m_pContent) - return 0; - - return m_pContent->GetSize(); + switch(m_type) { + case NodeType::Null: + case NodeType::Scalar: + return 0; + case NodeType::Sequence: + return m_seqData.size(); + case NodeType::Map: + return m_mapData.size(); + } + + assert(false); + return 0; } const Node *Node::FindAtIndex(std::size_t i) const { - if(!m_pContent) - return 0; - - return m_pContent->GetNode(i); + if(m_type == NodeType::Sequence) + return m_seqData[i]; + return 0; } bool Node::GetScalar(std::string& s) const { - if(!m_pContent) { - if(m_tag.empty()) + switch(m_type) { + case NodeType::Null: s = "~"; - else - s = ""; - return true; + return true; + case NodeType::Scalar: + s = m_scalarData; + return true; + case NodeType::Sequence: + case NodeType::Map: + return false; } - return m_pContent->GetScalar(s); + assert(false); + return false; } Emitter& operator << (Emitter& out, const Node& node) @@ -223,17 +225,41 @@ namespace YAML int Node::Compare(const Node& rhs) const { - // Step 1: no content is the smallest - if(!m_pContent) { - if(rhs.m_pContent) - return -1; - else + if(m_type != rhs.m_type) + return rhs.m_type - m_type; + + switch(m_type) { + case NodeType::Null: + return 0; + case NodeType::Scalar: + return m_scalarData.compare(rhs.m_scalarData); + case NodeType::Sequence: + if(m_seqData.size() < rhs.m_seqData.size()) + return 1; + else if(m_seqData.size() > rhs.m_seqData.size()) + return -1; + for(std::size_t i=0;iCompare(*rhs.m_seqData[i])) + return cmp; + return 0; + case NodeType::Map: + if(m_mapData.size() < rhs.m_mapData.size()) + return 1; + else if(m_mapData.size() > rhs.m_mapData.size()) + return -1; + node_map::const_iterator it = m_mapData.begin(); + node_map::const_iterator jt = rhs.m_mapData.begin(); + for(;it!=m_mapData.end() && jt!=rhs.m_mapData.end();it++, jt++) { + if(int cmp = it->first->Compare(*jt->first)) + return cmp; + if(int cmp = it->second->Compare(*jt->second)) + return cmp; + } return 0; } - if(!rhs.m_pContent) - return 1; - - return m_pContent->Compare(rhs.m_pContent); + + assert(false); + return 0; } bool operator < (const Node& n1, const Node& n2) diff --git a/src/nodebuilder.cpp b/src/nodebuilder.cpp index 447ff87..13a7032 100644 --- a/src/nodebuilder.cpp +++ b/src/nodebuilder.cpp @@ -1,7 +1,6 @@ #include "nodebuilder.h" #include "yaml-cpp/mark.h" #include "yaml-cpp/node.h" -#include "yaml-cpp/nodeproperties.h" #include namespace YAML @@ -25,32 +24,32 @@ namespace YAML assert(m_finished); } - void NodeBuilder::OnNull(const std::string& tag, anchor_t anchor) + void NodeBuilder::OnNull(const Mark& mark, anchor_t anchor) { Node& node = Push(anchor); - node.InitNull(tag); + node.Init(NodeType::Null, mark, ""); Pop(); } - void NodeBuilder::OnAlias(const Mark& mark, anchor_t anchor) + void NodeBuilder::OnAlias(const Mark& /*mark*/, anchor_t anchor) { - Node& node = Push(); - node.InitAlias(mark, *m_anchors[anchor]); - Pop(); + Node& node = *m_anchors[anchor]; + Insert(node); + node.MarkAsAliased(); } 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); + node.Init(NodeType::Scalar, mark, tag); + node.SetScalarData(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); + node.Init(NodeType::Sequence, mark, tag); } void NodeBuilder::OnSequenceEnd() @@ -61,7 +60,7 @@ namespace YAML void NodeBuilder::OnMapStart(const Mark& mark, const std::string& tag, anchor_t anchor) { Node& node = Push(anchor); - node.Init(CT_MAP, mark, tag); + node.Init(NodeType::Map, mark, tag); m_didPushKey.push(false); } @@ -85,14 +84,14 @@ namespace YAML return m_root; } - std::auto_ptr pNode(new Node); - m_stack.push(pNode); - return m_stack.top(); + Node& node = m_root.CreateNode(); + m_stack.push(&node); + return node; } Node& NodeBuilder::Top() { - return m_stack.empty() ? m_root : m_stack.top(); + return m_stack.empty() ? m_root : *m_stack.top(); } void NodeBuilder::Pop() @@ -103,36 +102,40 @@ namespace YAML return; } - std::auto_ptr pNode = m_stack.pop(); - Insert(pNode); + Node& node = *m_stack.top(); + m_stack.pop(); + Insert(node); } - void NodeBuilder::Insert(std::auto_ptr pNode) + void NodeBuilder::Insert(Node& node) { - Node& node = Top(); - switch(node.GetType()) { - case CT_SEQUENCE: - node.Append(pNode); + Node& curTop = Top(); + switch(curTop.Type()) { + case NodeType::Null: + case NodeType::Scalar: + assert(false); break; - case CT_MAP: + case NodeType::Sequence: + curTop.Append(node); + break; + case NodeType::Map: assert(!m_didPushKey.empty()); if(m_didPushKey.top()) { assert(!m_pendingKeys.empty()); - std::auto_ptr pKey = m_pendingKeys.pop(); - node.Insert(pKey, pNode); + Node& key = *m_pendingKeys.top(); + m_pendingKeys.pop(); + curTop.Insert(key, node); m_didPushKey.top() = false; } else { - m_pendingKeys.push(pNode); + m_pendingKeys.push(&node); m_didPushKey.top() = true; } break; - default: - assert(false); } } - void NodeBuilder::RegisterAnchor(anchor_t anchor, const Node& node) + void NodeBuilder::RegisterAnchor(anchor_t anchor, Node& node) { if(anchor) { assert(anchor == m_anchors.size()); diff --git a/src/nodebuilder.h b/src/nodebuilder.h index 1ecf2e3..eba403a 100644 --- a/src/nodebuilder.h +++ b/src/nodebuilder.h @@ -6,10 +6,10 @@ #endif #include "yaml-cpp/eventhandler.h" -#include "ptr_stack.h" #include #include #include +#include namespace YAML { @@ -24,7 +24,7 @@ namespace YAML virtual void OnDocumentStart(const Mark& mark); virtual void OnDocumentEnd(); - virtual void OnNull(const std::string& tag, anchor_t anchor); + virtual void OnNull(const Mark& mark, 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); @@ -40,19 +40,19 @@ namespace YAML Node& Top(); void Pop(); - void Insert(std::auto_ptr pNode); - void RegisterAnchor(anchor_t anchor, const Node& node); + void Insert(Node& node); + void RegisterAnchor(anchor_t anchor, Node& node); private: Node& m_root; bool m_initializedRoot; bool m_finished; - ptr_stack m_stack; - ptr_stack m_pendingKeys; + std::stack m_stack; + std::stack m_pendingKeys; std::stack m_didPushKey; - typedef std::vector Anchors; + typedef std::vector Anchors; Anchors m_anchors; }; } diff --git a/src/nodeownership.cpp b/src/nodeownership.cpp new file mode 100644 index 0000000..118edbc --- /dev/null +++ b/src/nodeownership.cpp @@ -0,0 +1,31 @@ +#include "nodeownership.h" +#include "yaml-cpp/node.h" + +namespace YAML +{ + NodeOwnership::NodeOwnership(NodeOwnership *pOwner): m_pOwner(pOwner) + { + if(!m_pOwner) + m_pOwner = this; + } + + NodeOwnership::~NodeOwnership() + { + } + + Node& NodeOwnership::_Create() + { + m_nodes.push_back(std::auto_ptr(new Node)); + return m_nodes.back(); + } + + void NodeOwnership::_MarkAsAliased(const Node& node) + { + m_aliasedNodes.insert(&node); + } + + bool NodeOwnership::_IsAliased(const Node& node) const + { + return m_aliasedNodes.count(&node) > 0; + } +} diff --git a/src/nodeownership.h b/src/nodeownership.h new file mode 100644 index 0000000..aae9b99 --- /dev/null +++ b/src/nodeownership.h @@ -0,0 +1,39 @@ +#ifndef NODE_OWNERSHIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define NODE_OWNERSHIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + + +#include "yaml-cpp/noncopyable.h" +#include "ptr_vector.h" +#include + +namespace YAML +{ + class Node; + + class NodeOwnership: private noncopyable + { + public: + explicit NodeOwnership(NodeOwnership *pOwner = 0); + ~NodeOwnership(); + + Node& Create() { return m_pOwner->_Create(); } + void MarkAsAliased(const Node& node) { m_pOwner->_MarkAsAliased(node); } + bool IsAliased(const Node& node) const { return m_pOwner->_IsAliased(node); } + + private: + Node& _Create(); + void _MarkAsAliased(const Node& node); + bool _IsAliased(const Node& node) const; + + private: + ptr_vector m_nodes; + std::set m_aliasedNodes; + NodeOwnership *m_pOwner; + }; +} + +#endif // NODE_OWNERSHIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/ptr_vector.h b/src/ptr_vector.h new file mode 100644 index 0000000..e798208 --- /dev/null +++ b/src/ptr_vector.h @@ -0,0 +1,45 @@ +#ifndef PTR_VECTOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define PTR_VECTOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/noncopyable.h" +#include +#include + +namespace YAML { + + template + class ptr_vector: private YAML::noncopyable + { + public: + ptr_vector() {} + ~ptr_vector() { clear(); } + + void clear() { + for(unsigned i=0;i t) { + m_data.push_back(NULL); + m_data.back() = t.release(); + } + T& operator[](std::size_t i) { return *m_data[i]; } + const T& operator[](std::size_t i) const { return *m_data[i]; } + + T& back() { return *m_data.back(); } + const T& back() const { return *m_data.back(); } + + private: + std::vector m_data; + }; +} + +#endif // PTR_VECTOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/scalar.cpp b/src/scalar.cpp deleted file mode 100644 index 8bba6f7..0000000 --- a/src/scalar.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "scalar.h" -#include "yaml-cpp/eventhandler.h" - -namespace YAML -{ - Scalar::Scalar() - { - } - - Scalar::~Scalar() - { - } - - void Scalar::EmitEvents(AliasManager&, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const - { - eventHandler.OnScalar(mark, tag, anchor, m_data); - } - - int Scalar::Compare(Content *pContent) - { - return -pContent->Compare(this); - } - - int Scalar::Compare(Scalar *pScalar) - { - if(m_data < pScalar->m_data) - return -1; - else if(m_data > pScalar->m_data) - return 1; - else - return 0; - } -} - diff --git a/src/scalar.h b/src/scalar.h deleted file mode 100644 index 0cca420..0000000 --- a/src/scalar.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef SCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#define SCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 - -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 -#pragma once -#endif - - -#include "content.h" -#include - -namespace YAML -{ - class Scalar: public Content - { - public: - Scalar(); - virtual ~Scalar(); - - 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 { - scalar = m_data; - return true; - } - - // ordering - virtual int Compare(Content *pContent); - virtual int Compare(Scalar *pScalar); - virtual int Compare(Sequence *) { return -1; } - virtual int Compare(Map *) { return -1; } - - protected: - std::string m_data; - }; -} - -#endif // SCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 - diff --git a/src/sequence.cpp b/src/sequence.cpp deleted file mode 100644 index 41e3710..0000000 --- a/src/sequence.cpp +++ /dev/null @@ -1,83 +0,0 @@ -#include "sequence.h" -#include "yaml-cpp/eventhandler.h" -#include "yaml-cpp/node.h" -#include - -namespace YAML -{ - Sequence::Sequence() - { - - } - - Sequence::~Sequence() - { - Clear(); - } - - void Sequence::Clear() - { - for(std::size_t i=0;i::const_iterator& it) const - { - it = m_data.begin(); - return true; - } - - bool Sequence::GetEnd(std::vector ::const_iterator& it) const - { - it = m_data.end(); - return true; - } - - Node *Sequence::GetNode(std::size_t i) const - { - if(i < m_data.size()) - return m_data[i]; - return 0; - } - - std::size_t Sequence::GetSize() const - { - return m_data.size(); - } - - void Sequence::Append(std::auto_ptr pNode) - { - m_data.push_back(pNode.release()); - } - - void Sequence::EmitEvents(AliasManager& am, EventHandler& eventHandler, const Mark& mark, const std::string& tag, anchor_t anchor) const - { - eventHandler.OnSequenceStart(mark, tag, anchor); - for(std::size_t i=0;iEmitEvents(am, eventHandler); - eventHandler.OnSequenceEnd(); - } - - int Sequence::Compare(Content *pContent) - { - return -pContent->Compare(this); - } - - int Sequence::Compare(Sequence *pSeq) - { - std::size_t n = m_data.size(), m = pSeq->m_data.size(); - if(n < m) - return -1; - else if(n > m) - return 1; - - for(std::size_t i=0;iCompare(*pSeq->m_data[i]); - if(cmp != 0) - return cmp; - } - - return 0; - } -} diff --git a/src/sequence.h b/src/sequence.h deleted file mode 100644 index 2078d19..0000000 --- a/src/sequence.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef SEQUENCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#define SEQUENCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 - -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 -#pragma once -#endif - - -#include "content.h" -#include - -namespace YAML -{ - class Node; - - class Sequence: public Content - { - public: - Sequence(); - virtual ~Sequence(); - - void Clear(); - - virtual bool GetBegin(std::vector ::const_iterator& it) const; - virtual bool GetEnd(std::vector ::const_iterator& it) const; - virtual Node *GetNode(std::size_t i) const; - virtual std::size_t GetSize() const; - - virtual void Append(std::auto_ptr 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; } - - // ordering - virtual int Compare(Content *pContent); - virtual int Compare(Scalar *) { return 1; } - virtual int Compare(Sequence *pSeq); - virtual int Compare(Map *) { return -1; } - - protected: - std::vector m_data; - }; -} - -#endif // SEQUENCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/singledocparser.cpp b/src/singledocparser.cpp index c67a0ff..47759c3 100644 --- a/src/singledocparser.cpp +++ b/src/singledocparser.cpp @@ -48,7 +48,7 @@ namespace YAML { // an empty node *is* a possibility if(m_scanner.empty()) { - eventHandler.OnNull("", NullAnchor); + eventHandler.OnNull(Mark::null(), NullAnchor); return; } @@ -112,7 +112,10 @@ namespace YAML break; } - eventHandler.OnNull(tag, anchor); + if(tag == "?") + eventHandler.OnNull(mark, anchor); + else + eventHandler.OnScalar(mark, tag, anchor, ""); } void SingleDocParser::HandleSequence(EventHandler& eventHandler) @@ -147,7 +150,7 @@ namespace YAML 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); + eventHandler.OnNull(token.mark, NullAnchor); continue; } } @@ -224,7 +227,7 @@ namespace YAML m_scanner.pop(); HandleNode(eventHandler); } else { - eventHandler.OnNull("", NullAnchor); + eventHandler.OnNull(token.mark, NullAnchor); } // now grab value (optional) @@ -232,7 +235,7 @@ namespace YAML m_scanner.pop(); HandleNode(eventHandler); } else { - eventHandler.OnNull("", NullAnchor); + eventHandler.OnNull(token.mark, NullAnchor); } } @@ -261,7 +264,7 @@ namespace YAML m_scanner.pop(); HandleNode(eventHandler); } else { - eventHandler.OnNull("", NullAnchor); + eventHandler.OnNull(token.mark, NullAnchor); } // now grab value (optional) @@ -269,7 +272,7 @@ namespace YAML m_scanner.pop(); HandleNode(eventHandler); } else { - eventHandler.OnNull("", NullAnchor); + eventHandler.OnNull(token.mark, NullAnchor); } // now eat the separator (or could be a map end, which we ignore - but if it's neither, then it's a bad node) @@ -289,6 +292,7 @@ namespace YAML m_pCollectionStack->PushCollectionType(CollectionType::CompactMap); // grab key + Mark mark = m_scanner.peek().mark; m_scanner.pop(); HandleNode(eventHandler); @@ -297,7 +301,7 @@ namespace YAML m_scanner.pop(); HandleNode(eventHandler); } else { - eventHandler.OnNull("", NullAnchor); + eventHandler.OnNull(mark, NullAnchor); } m_pCollectionStack->PopCollectionType(CollectionType::CompactMap); @@ -309,7 +313,7 @@ namespace YAML m_pCollectionStack->PushCollectionType(CollectionType::CompactMap); // null key - eventHandler.OnNull("", NullAnchor); + eventHandler.OnNull(m_scanner.peek().mark, NullAnchor); // grab value m_scanner.pop(); diff --git a/test/parsertests.cpp b/test/parsertests.cpp index 9393208..74e0801 100644 --- a/test/parsertests.cpp +++ b/test/parsertests.cpp @@ -698,7 +698,7 @@ namespace Test YAML::Node doc; parser.GetNextDocument(doc); - if(doc["a"] != 1) + if(doc["a"] != 4) return false; if(doc["b"] != 2) return false; @@ -729,10 +729,10 @@ namespace Test bool ExpectedTagValue(YAML::Node& node, const char* tag) { - if(node.GetTag() == tag) + if(node.Tag() == tag) return true; - throw TagMismatch(node.GetTag(), tag); + throw TagMismatch(node.Tag(), tag); } bool DefaultPlainScalarTag() diff --git a/test/spectests.cpp b/test/spectests.cpp index 106de80..719dea2 100644 --- a/test/spectests.cpp +++ b/test/spectests.cpp @@ -481,16 +481,16 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["not-date"].GetTag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(doc["not-date"].Tag() == "tag:yaml.org,2002:str"); YAML_ASSERT(doc["not-date"] == "2002-04-28"); - YAML_ASSERT(doc["picture"].GetTag() == "tag:yaml.org,2002:binary"); + YAML_ASSERT(doc["picture"].Tag() == "tag:yaml.org,2002:binary"); YAML_ASSERT(doc["picture"] == "R0lGODlhDAAMAIQAAP//9/X\n" "17unp5WZmZgAAAOfn515eXv\n" "Pz7Y6OjuDg4J+fn5OTk6enp\n" "56enmleECcgggoBADs=\n" ); - YAML_ASSERT(doc["application specific tag"].GetTag() == "!something"); + YAML_ASSERT(doc["application specific tag"].Tag() == "!something"); YAML_ASSERT(doc["application specific tag"] == "The semantics of the tag\n" "above may be different for\n" @@ -519,15 +519,15 @@ namespace Test { " text: Pretty vector drawing."; PARSE(doc, input); - YAML_ASSERT(doc.GetTag() == "tag:clarkevans.com,2002:shape"); + YAML_ASSERT(doc.Tag() == "tag:clarkevans.com,2002:shape"); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc[0].GetTag() == "tag:clarkevans.com,2002:circle"); + YAML_ASSERT(doc[0].Tag() == "tag:clarkevans.com,2002:circle"); YAML_ASSERT(doc[0].size() == 2); YAML_ASSERT(doc[0]["center"].size() == 2); YAML_ASSERT(doc[0]["center"]["x"] == 73); YAML_ASSERT(doc[0]["center"]["y"] == 129); YAML_ASSERT(doc[0]["radius"] == 7); - YAML_ASSERT(doc[1].GetTag() == "tag:clarkevans.com,2002:line"); + YAML_ASSERT(doc[1].Tag() == "tag:clarkevans.com,2002:line"); YAML_ASSERT(doc[1].size() == 2); YAML_ASSERT(doc[1]["start"].size() == 2); YAML_ASSERT(doc[1]["start"]["x"] == 73); @@ -535,7 +535,7 @@ namespace Test { YAML_ASSERT(doc[1]["finish"].size() == 2); YAML_ASSERT(doc[1]["finish"]["x"] == 89); YAML_ASSERT(doc[1]["finish"]["y"] == 102); - YAML_ASSERT(doc[2].GetTag() == "tag:clarkevans.com,2002:label"); + YAML_ASSERT(doc[2].Tag() == "tag:clarkevans.com,2002:label"); YAML_ASSERT(doc[2].size() == 3); YAML_ASSERT(doc[2]["start"].size() == 2); YAML_ASSERT(doc[2]["start"]["x"] == 73); @@ -558,7 +558,7 @@ namespace Test { "? Ken Griffey"; PARSE(doc, input); - YAML_ASSERT(doc.GetTag() == "tag:yaml.org,2002:set"); + YAML_ASSERT(doc.Tag() == "tag:yaml.org,2002:set"); YAML_ASSERT(doc.size() == 3); YAML_ASSERT(IsNull(doc["Mark McGwire"])); YAML_ASSERT(IsNull(doc["Sammy Sosa"])); @@ -579,7 +579,7 @@ namespace Test { "- Ken Griffey: 58"; PARSE(doc, input); - YAML_ASSERT(doc.GetTag() == "tag:yaml.org,2002:omap"); + YAML_ASSERT(doc.Tag() == "tag:yaml.org,2002:omap"); YAML_ASSERT(doc.size() == 3); YAML_ASSERT(doc[0].size() == 1); YAML_ASSERT(doc[0]["Mark McGwire"] == 65); @@ -625,7 +625,7 @@ namespace Test { " Billsmer @ 338-4338."; PARSE(doc, input); - YAML_ASSERT(doc.GetTag() == "tag:clarkevans.com,2002:invoice"); + YAML_ASSERT(doc.Tag() == "tag:clarkevans.com,2002:invoice"); YAML_ASSERT(doc.size() == 8); YAML_ASSERT(doc["invoice"] == 34843); YAML_ASSERT(doc["date"] == "2001-01-23"); @@ -1185,7 +1185,7 @@ namespace Test { "!yaml!str \"foo\""; PARSE(doc, input); - YAML_ASSERT(doc.GetTag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(doc.Tag() == "tag:yaml.org,2002:str"); YAML_ASSERT(doc == "foo"); return true; } @@ -1223,11 +1223,11 @@ namespace Test { "!foo \"bar\""; PARSE(doc, input); - YAML_ASSERT(doc.GetTag() == "!foo"); + YAML_ASSERT(doc.Tag() == "!foo"); YAML_ASSERT(doc == "bar"); PARSE_NEXT(doc); - YAML_ASSERT(doc.GetTag() == "tag:example.com,2000:app/foo"); + YAML_ASSERT(doc.Tag() == "tag:example.com,2000:app/foo"); YAML_ASSERT(doc == "bar"); return true; } @@ -1241,7 +1241,7 @@ namespace Test { "!!int 1 - 3 # Interval, not integer"; PARSE(doc, input); - YAML_ASSERT(doc.GetTag() == "tag:example.com,2000:app/int"); + YAML_ASSERT(doc.Tag() == "tag:example.com,2000:app/int"); YAML_ASSERT(doc == "1 - 3"); return true; } @@ -1255,7 +1255,7 @@ namespace Test { "!e!foo \"bar\""; PARSE(doc, input); - YAML_ASSERT(doc.GetTag() == "tag:example.com,2000:app/foo"); + YAML_ASSERT(doc.Tag() == "tag:example.com,2000:app/foo"); YAML_ASSERT(doc == "bar"); return true; } @@ -1273,11 +1273,11 @@ namespace Test { "!m!light green"; PARSE(doc, input); - YAML_ASSERT(doc.GetTag() == "!my-light"); + YAML_ASSERT(doc.Tag() == "!my-light"); YAML_ASSERT(doc == "fluorescent"); PARSE_NEXT(doc); - YAML_ASSERT(doc.GetTag() == "!my-light"); + YAML_ASSERT(doc.Tag() == "!my-light"); YAML_ASSERT(doc == "green"); return true; } @@ -1292,7 +1292,7 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 1); - YAML_ASSERT(doc[0].GetTag() == "tag:example.com,2000:app/foo"); + YAML_ASSERT(doc[0].Tag() == "tag:example.com,2000:app/foo"); YAML_ASSERT(doc[0] == "bar"); return true; } @@ -1309,8 +1309,8 @@ namespace Test { YAML_ASSERT(doc.size() == 2); for(YAML::Iterator it=doc.begin();it!=doc.end();++it) { if(it.first() == "foo") { - YAML_ASSERT(it.first().GetTag() == "tag:yaml.org,2002:str"); - YAML_ASSERT(it.second().GetTag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(it.first().Tag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(it.second().Tag() == "tag:yaml.org,2002:str"); YAML_ASSERT(it.second() == "bar"); } else if(it.first() == "baz") { YAML_ASSERT(it.second() == "foo"); @@ -1331,9 +1331,9 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 1); for(YAML::Iterator it=doc.begin();it!=doc.end();++it) { - YAML_ASSERT(it.first().GetTag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(it.first().Tag() == "tag:yaml.org,2002:str"); YAML_ASSERT(it.first() == "foo"); - YAML_ASSERT(it.second().GetTag() == "!bar"); + YAML_ASSERT(it.second().Tag() == "!bar"); YAML_ASSERT(it.second() == "baz"); } return true; @@ -1362,11 +1362,11 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc[0].GetTag() == "!local"); + YAML_ASSERT(doc[0].Tag() == "!local"); YAML_ASSERT(doc[0] == "foo"); - YAML_ASSERT(doc[1].GetTag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(doc[1].Tag() == "tag:yaml.org,2002:str"); YAML_ASSERT(doc[1] == "bar"); - YAML_ASSERT(doc[2].GetTag() == "tag:example.com,2000:app/tag%21"); + YAML_ASSERT(doc[2].Tag() == "tag:example.com,2000:app/tag%21"); YAML_ASSERT(doc[2] == "baz"); return true; } @@ -1462,10 +1462,10 @@ namespace Test { YAML_ASSERT(doc.size() == 2); for(YAML::Iterator it=doc.begin();it!=doc.end();++it) { if(it.first() == "foo") { - YAML_ASSERT(it.second().GetTag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(it.second().Tag() == "tag:yaml.org,2002:str"); YAML_ASSERT(it.second() == ""); } else if(it.first() == "") { - YAML_ASSERT(it.first().GetTag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(it.first().Tag() == "tag:yaml.org,2002:str"); YAML_ASSERT(it.second() == "bar"); } else return " unexpected key"; @@ -1862,12 +1862,12 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 5); - YAML_ASSERT(doc[0].GetTag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(doc[0].Tag() == "tag:yaml.org,2002:str"); YAML_ASSERT(doc[0] == "a"); YAML_ASSERT(doc[1] == 'b'); YAML_ASSERT(doc[2] == "c"); YAML_ASSERT(doc[3] == "c"); - YAML_ASSERT(doc[4].GetTag() == "tag:yaml.org,2002:str"); + YAML_ASSERT(doc[4].Tag() == "tag:yaml.org,2002:str"); YAML_ASSERT(doc[4] == ""); return true; } diff --git a/util/parse.cpp b/util/parse.cpp index f8cdb52..8f194f0 100644 --- a/util/parse.cpp +++ b/util/parse.cpp @@ -23,7 +23,7 @@ public: virtual void OnDocumentStart(const YAML::Mark&) {} virtual void OnDocumentEnd() {} - virtual void OnNull(const std::string&, YAML::anchor_t) {} + virtual void OnNull(const YAML::Mark&, YAML::anchor_t) {} virtual void OnAlias(const YAML::Mark&, YAML::anchor_t) {} virtual void OnScalar(const YAML::Mark&, const std::string&, YAML::anchor_t, const std::string&) {} From 9419d411f86897b7cb3e7ff9b320dc04d59fd3a0 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 3 Mar 2011 02:38:35 +0000 Subject: [PATCH 258/295] Set the precision of emitting float/double to 15 --- include/yaml-cpp/emitter.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/yaml-cpp/emitter.h b/include/yaml-cpp/emitter.h index f7ec3e1..bc3a31c 100644 --- a/include/yaml-cpp/emitter.h +++ b/include/yaml-cpp/emitter.h @@ -116,6 +116,7 @@ namespace YAML EmitSeparationIfNecessary(); std::stringstream str; + str.precision(15); str << value; m_stream << str.str(); From bf2bb91dc6d79412aeab7a6922de6fc487af5a25 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 3 Mar 2011 03:37:54 +0000 Subject: [PATCH 259/295] Compressed the sequence-of-maps emitting (got rid of the unnecessary newline) - issue 61 --- src/emitter.cpp | 40 +++++++++++++++++++++++++--------------- src/emitterstate.cpp | 2 +- src/emitterstate.h | 12 ++++++++---- test/emittertests.cpp | 22 +++++++++++----------- 4 files changed, 45 insertions(+), 31 deletions(-) diff --git a/src/emitter.cpp b/src/emitter.cpp index 8dcc45c..d65fd0b 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -153,16 +153,19 @@ namespace YAML // document-level case ES_WAITING_FOR_DOC: m_stream << "---"; - m_pState->RequireSeparation(); + m_pState->RequireSoftSeparation(); m_pState->SwitchState(ES_WRITING_DOC); return true; case ES_WRITING_DOC: return true; + case ES_DONE_WITH_DOC: + m_pState->SetError("Write called on finished document"); + return true; // block sequence case ES_WAITING_FOR_BLOCK_SEQ_ENTRY: m_stream << IndentTo(curIndent) << "-"; - m_pState->RequireSeparation(); + m_pState->RequireSoftSeparation(); m_pState->SwitchState(ES_WRITING_BLOCK_SEQ_ENTRY); return true; case ES_WRITING_BLOCK_SEQ_ENTRY: @@ -180,7 +183,7 @@ namespace YAML return true; case ES_DONE_WITH_FLOW_SEQ_ENTRY: m_stream << ','; - m_pState->RequireSeparation(); + m_pState->RequireSoftSeparation(); m_pState->SwitchState(ES_WAITING_FOR_FLOW_SEQ_ENTRY); return false; @@ -191,7 +194,7 @@ namespace YAML case ES_WAITING_FOR_BLOCK_MAP_KEY: if(m_pState->CurrentlyInLongKey()) { m_stream << IndentTo(curIndent) << '?'; - m_pState->RequireSeparation(); + m_pState->RequireSoftSeparation(); } m_pState->SwitchState(ES_WRITING_BLOCK_MAP_KEY); return true; @@ -218,7 +221,7 @@ namespace YAML if(m_pState->CurrentlyInLongKey()) { EmitSeparationIfNecessary(); m_stream << '?'; - m_pState->RequireSeparation(); + m_pState->RequireSoftSeparation(); } return true; case ES_WRITING_FLOW_MAP_KEY: @@ -228,7 +231,7 @@ namespace YAML return true; case ES_WAITING_FOR_FLOW_MAP_VALUE: m_stream << ':'; - m_pState->RequireSeparation(); + m_pState->RequireSoftSeparation(); m_pState->SwitchState(ES_WRITING_FLOW_MAP_VALUE); return true; case ES_WRITING_FLOW_MAP_VALUE: @@ -284,7 +287,7 @@ namespace YAML case ES_WRITING_BLOCK_MAP_KEY: if(!m_pState->CurrentlyInLongKey()) { m_stream << ':'; - m_pState->RequireSeparation(); + m_pState->RequireSoftSeparation(); } m_pState->SwitchState(ES_DONE_WITH_BLOCK_MAP_KEY); break; @@ -312,8 +315,10 @@ namespace YAML if(!good()) return; - if(m_pState->RequiresSeparation()) + if(m_pState->RequiresSoftSeparation()) m_stream << ' '; + else if(m_pState->RequiresHardSeparation()) + m_stream << '\n'; m_pState->UnsetSeparation(); } @@ -403,8 +408,10 @@ namespace YAML curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE || curState == ES_WRITING_DOC ) { - m_stream << "\n"; - m_pState->UnsetSeparation(); + if(m_pState->RequiresHardSeparation() || curState != ES_WRITING_BLOCK_SEQ_ENTRY) { + m_stream << "\n"; + m_pState->UnsetSeparation(); + } } m_pState->PushState(ES_WAITING_FOR_BLOCK_MAP_ENTRY); } else if(flowType == Flow) { @@ -469,11 +476,12 @@ namespace YAML m_stream << '\n'; unsigned curIndent = m_pState->GetCurIndent(); m_stream << IndentTo(curIndent); + m_pState->UnsetSeparation(); m_pState->SwitchState(ES_WAITING_FOR_BLOCK_MAP_KEY); } else if(flowType == FT_FLOW) { if(curState == ES_DONE_WITH_FLOW_MAP_VALUE) { m_stream << ','; - m_pState->RequireSeparation(); + m_pState->RequireSoftSeparation(); } m_pState->SwitchState(ES_WAITING_FOR_FLOW_MAP_KEY); } else @@ -503,7 +511,7 @@ namespace YAML m_stream << '\n'; m_stream << IndentTo(m_pState->GetCurIndent()); m_stream << ':'; - m_pState->RequireSeparation(); + m_pState->RequireSoftSeparation(); } m_pState->SwitchState(ES_WAITING_FOR_BLOCK_MAP_VALUE); } else if(flowType == FT_FLOW) { @@ -518,8 +526,10 @@ namespace YAML if(!good()) return; - if(CanEmitNewline()) + if(CanEmitNewline()) { m_stream << '\n'; + m_pState->UnsetSeparation(); + } } bool Emitter::CanEmitNewline() const @@ -685,7 +695,7 @@ namespace YAML m_pState->SetError(ErrorMsg::INVALID_ANCHOR); return *this; } - m_pState->RequireSeparation(); + m_pState->RequireHardSeparation(); // Note: no PostAtomicWrite() because we need another value for this node return *this; } @@ -711,7 +721,7 @@ namespace YAML return *this; } - m_pState->RequireSeparation(); + m_pState->RequireHardSeparation(); // Note: no PostAtomicWrite() because we need another value for this node return *this; } diff --git a/src/emitterstate.cpp b/src/emitterstate.cpp index 1214ac5..6b8476f 100644 --- a/src/emitterstate.cpp +++ b/src/emitterstate.cpp @@ -3,7 +3,7 @@ namespace YAML { - EmitterState::EmitterState(): m_isGood(true), m_curIndent(0), m_requiresSeparation(false) + EmitterState::EmitterState(): m_isGood(true), m_curIndent(0), m_requiresSoftSeparation(false), m_requiresHardSeparation(false) { // start up m_stateStack.push(ES_WAITING_FOR_DOC); diff --git a/src/emitterstate.h b/src/emitterstate.h index 5df5008..697aafc 100644 --- a/src/emitterstate.h +++ b/src/emitterstate.h @@ -103,9 +103,12 @@ namespace YAML void StartLongKey(); void StartSimpleKey(); - bool RequiresSeparation() const { return m_requiresSeparation; } - void RequireSeparation() { m_requiresSeparation = true; } - void UnsetSeparation() { m_requiresSeparation = false; } + bool RequiresSoftSeparation() const { return m_requiresSoftSeparation; } + bool RequiresHardSeparation() const { return m_requiresHardSeparation; } + void RequireSoftSeparation() { m_requiresSoftSeparation = true; } + void RequireHardSeparation() { m_requiresSoftSeparation = true; m_requiresHardSeparation = true; } + void ForceHardSeparation() { m_requiresSoftSeparation = false; } + void UnsetSeparation() { m_requiresSoftSeparation = false; m_requiresHardSeparation = false; } void ClearModifiedSettings(); @@ -184,7 +187,8 @@ namespace YAML std::stack m_groups; unsigned m_curIndent; - bool m_requiresSeparation; + bool m_requiresSoftSeparation; + bool m_requiresHardSeparation; }; template diff --git a/test/emittertests.cpp b/test/emittertests.cpp index 16f8764..9f81e33 100644 --- a/test/emittertests.cpp +++ b/test/emittertests.cpp @@ -103,7 +103,7 @@ namespace Test out << "item 2"; out << YAML::EndSeq; - desiredOutput = "---\n- item 1\n-\n pens: 8\n pencils: 14\n- item 2"; + desiredOutput = "---\n- item 1\n- pens: 8\n pencils: 14\n- item 2"; } void NestedBlockMap(YAML::Emitter& out, std::string& desiredOutput) { @@ -451,7 +451,7 @@ namespace Test out << YAML::Value << YAML::Alias("id001"); out << YAML::EndMap; - desiredOutput = "---\nreceipt: Oz-Ware Purchase Invoice\ndate: 2007-08-06\ncustomer:\n given: Dorothy\n family: Gale\nitems:\n -\n part_no: A4786\n descrip: Water Bucket (Filled)\n price: 1.47\n quantity: 4\n -\n part_no: E1628\n descrip: High Heeled \"Ruby\" Slippers\n price: 100.27\n quantity: 1\nbill-to: &id001\n street: |\n 123 Tornado Alley\n Suite 16\n city: East Westville\n state: KS\nship-to: *id001"; + desiredOutput = "---\nreceipt: Oz-Ware Purchase Invoice\ndate: 2007-08-06\ncustomer:\n given: Dorothy\n family: Gale\nitems:\n - part_no: A4786\n descrip: Water Bucket (Filled)\n price: 1.47\n quantity: 4\n - part_no: E1628\n descrip: High Heeled \"Ruby\" Slippers\n price: 100.27\n quantity: 1\nbill-to: &id001\n street: |\n 123 Tornado Alley\n Suite 16\n city: East Westville\n state: KS\nship-to: *id001"; } void STLContainers(YAML::Emitter& out, std::string& desiredOutput) @@ -471,7 +471,7 @@ namespace Test out << ages; out << YAML::EndSeq; - desiredOutput = "---\n- [2, 3, 5, 7, 11, 13]\n-\n Daniel: 26\n Jesse: 24"; + desiredOutput = "---\n- [2, 3, 5, 7, 11, 13]\n- Daniel: 26\n Jesse: 24"; } void SimpleComment(YAML::Emitter& out, std::string& desiredOutput) @@ -514,7 +514,7 @@ namespace Test out << YAML::EndMap; out << YAML::EndSeq; - desiredOutput = "---\n-\n key 1: value 1\n key 2:\n - a\n - b\n - c"; + desiredOutput = "---\n- key 1: value 1\n key 2:\n - a\n - b\n - c"; } void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) @@ -529,7 +529,7 @@ namespace Test out << YAML::EndMap; out << YAML::EndSeq; - desiredOutput = "---\n-\n ? key 1\n : value 1\n ? key 2\n : [a, b, c]"; + desiredOutput = "---\n- ? key 1\n : value 1\n ? key 2\n : [a, b, c]"; } void ComplexGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) @@ -548,7 +548,7 @@ namespace Test out << YAML::EndMap; out << YAML::EndSeq; - desiredOutput = "---\n-\n key 1: value 1\n key 2: [a, b, c]\n-\n ? [1, 2]\n :\n a: b"; + desiredOutput = "---\n- key 1: value 1\n key 2: [a, b, c]\n- ? [1, 2]\n :\n a: b"; } void Null(YAML::Emitter& out, std::string& desiredOutput) @@ -561,7 +561,7 @@ namespace Test out << YAML::EndMap; out << YAML::EndSeq; - desiredOutput = "---\n- ~\n-\n null value: ~\n ~: null key"; + desiredOutput = "---\n- ~\n- null value: ~\n ~: null key"; } void EscapedUnicode(YAML::Emitter& out, std::string& desiredOutput) @@ -606,7 +606,7 @@ namespace Test out << Foo(3, "goodbye"); out << YAML::EndSeq; - desiredOutput = "---\n-\n x: 5\n bar: hello\n-\n x: 3\n bar: goodbye"; + desiredOutput = "---\n- x: 5\n bar: hello\n- x: 3\n bar: goodbye"; } void UserTypeInContainer(YAML::Emitter& out, std::string& desiredOutput) @@ -616,7 +616,7 @@ namespace Test fv.push_back(Foo(3, "goodbye")); out << fv; - desiredOutput = "---\n-\n x: 5\n bar: hello\n-\n x: 3\n bar: goodbye"; + desiredOutput = "---\n- x: 5\n bar: hello\n- x: 3\n bar: goodbye"; } template @@ -649,7 +649,7 @@ namespace Test out << bar << baz; out << YAML::EndSeq; - desiredOutput = "---\n-\n x: 5\n bar: hello\n- ~"; + desiredOutput = "---\n- x: 5\n bar: hello\n- ~"; } void NewlineAtEnd(YAML::Emitter& out, std::string& desiredOutput) @@ -706,7 +706,7 @@ namespace Test out << YAML::LongKey << YAML::Key << "f" << YAML::Newline << YAML::Value << "foo"; out << YAML::EndMap; out << YAML::EndSeq; - desiredOutput = "---\n- a\n\n-\n - b\n - c\n\n\n-\n\n d: e\n ? f\n\n : foo"; + desiredOutput = "---\n- a\n\n-\n - b\n - c\n\n\n-\n d: e\n ? f\n\n : foo"; } void Binary(YAML::Emitter& out, std::string& desiredOutput) From bbb19cf5c00df9c049be53487e0f38df611deb03 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 3 Mar 2011 08:04:30 +0000 Subject: [PATCH 260/295] Added parsing of output to emitter tests --- test/emittertests.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/emittertests.cpp b/test/emittertests.cpp index 9f81e33..b4114e0 100644 --- a/test/emittertests.cpp +++ b/test/emittertests.cpp @@ -872,7 +872,16 @@ namespace Test std::string output = out.c_str(); if(output == desiredOutput) { - passed++; + try { + std::stringstream stream(output); + YAML::Parser parser; + YAML::Node node; + parser.GetNextDocument(node); + passed++; + } catch(const YAML::Exception& e) { + std::cout << "Emitter test failed: " << name << "\n"; + std::cout << "Parsing output error: " << e.what() << "\n"; + } } else { std::cout << "Emitter test failed: " << name << "\n"; std::cout << "Output:\n"; From 06eae35c316a8c92e38439d72206bbd40e05fbad Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 3 Mar 2011 08:11:14 +0000 Subject: [PATCH 261/295] Switched the emitter state's stack of groups to a ptr_stack --- src/emitterstate.cpp | 32 ++++++++++---------------------- src/emitterstate.h | 31 +++++++++++++++---------------- src/ptr_stack.h | 1 + 3 files changed, 26 insertions(+), 38 deletions(-) diff --git a/src/emitterstate.cpp b/src/emitterstate.cpp index 6b8476f..dfe2b2b 100644 --- a/src/emitterstate.cpp +++ b/src/emitterstate.cpp @@ -25,18 +25,6 @@ namespace YAML EmitterState::~EmitterState() { - while(!m_groups.empty()) - _PopGroup(); - } - - std::auto_ptr EmitterState::_PopGroup() - { - if(m_groups.empty()) - return std::auto_ptr (0); - - std::auto_ptr pGroup(m_groups.top()); - m_groups.pop(); - return pGroup; } // SetLocalValue @@ -57,10 +45,10 @@ namespace YAML void EmitterState::BeginGroup(GROUP_TYPE type) { - unsigned lastIndent = (m_groups.empty() ? 0 : m_groups.top()->indent); + unsigned lastIndent = (m_groups.empty() ? 0 : m_groups.top().indent); m_curIndent += lastIndent; - std::auto_ptr pGroup(new Group(type)); + std::auto_ptr pGroup(new Group(type)); // transfer settings (which last until this group is done) pGroup->modifiedSettings = m_modifiedSettings; @@ -70,7 +58,7 @@ namespace YAML pGroup->indent = GetIndent(); pGroup->usingLongKey = (GetMapKeyFormat() == LongKey ? true : false); - m_groups.push(pGroup.release()); + m_groups.push(pGroup); } void EmitterState::EndGroup(GROUP_TYPE type) @@ -80,13 +68,13 @@ namespace YAML // get rid of the current group { - std::auto_ptr pFinishedGroup = _PopGroup(); + std::auto_ptr pFinishedGroup = m_groups.pop(); if(pFinishedGroup->type != type) return SetError(ErrorMsg::UNMATCHED_GROUP_TAG); } // reset old settings - unsigned lastIndent = (m_groups.empty() ? 0 : m_groups.top()->indent); + unsigned lastIndent = (m_groups.empty() ? 0 : m_groups.top().indent); assert(m_curIndent >= lastIndent); m_curIndent -= lastIndent; @@ -100,7 +88,7 @@ namespace YAML if(m_groups.empty()) return GT_NONE; - return m_groups.top()->type; + return m_groups.top().type; } FLOW_TYPE EmitterState::GetCurGroupFlowType() const @@ -108,26 +96,26 @@ namespace YAML if(m_groups.empty()) return FT_NONE; - return (m_groups.top()->flow == Flow ? FT_FLOW : FT_BLOCK); + return (m_groups.top().flow == Flow ? FT_FLOW : FT_BLOCK); } bool EmitterState::CurrentlyInLongKey() { if(m_groups.empty()) return false; - return m_groups.top()->usingLongKey; + return m_groups.top().usingLongKey; } void EmitterState::StartLongKey() { if(!m_groups.empty()) - m_groups.top()->usingLongKey = true; + m_groups.top().usingLongKey = true; } void EmitterState::StartSimpleKey() { if(!m_groups.empty()) - m_groups.top()->usingLongKey = false; + m_groups.top().usingLongKey = false; } void EmitterState::ClearModifiedSettings() diff --git a/src/emitterstate.h b/src/emitterstate.h index 697aafc..9c8136e 100644 --- a/src/emitterstate.h +++ b/src/emitterstate.h @@ -6,6 +6,7 @@ #endif +#include "ptr_stack.h" #include "setting.h" #include "yaml-cpp/emittermanip.h" #include @@ -155,19 +156,19 @@ namespace YAML std::string m_lastError; // other state - std::stack m_stateStack; + std::stack m_stateStack; - Setting m_charset; - Setting m_strFmt; - Setting m_boolFmt; - Setting m_boolLengthFmt; - Setting m_boolCaseFmt; - Setting m_intFmt; - Setting m_indent; - Setting m_preCommentIndent, m_postCommentIndent; - Setting m_seqFmt; - Setting m_mapFmt; - Setting m_mapKeyFmt; + Setting m_charset; + Setting m_strFmt; + Setting m_boolFmt; + Setting m_boolLengthFmt; + Setting m_boolCaseFmt; + Setting m_intFmt; + Setting m_indent; + Setting m_preCommentIndent, m_postCommentIndent; + Setting m_seqFmt; + Setting m_mapFmt; + Setting m_mapKeyFmt; SettingChanges m_modifiedSettings; SettingChanges m_globalModifiedSettings; @@ -182,10 +183,8 @@ namespace YAML SettingChanges modifiedSettings; }; - - std::auto_ptr _PopGroup(); - - std::stack m_groups; + + ptr_stack m_groups; unsigned m_curIndent; bool m_requiresSoftSeparation; bool m_requiresHardSeparation; diff --git a/src/ptr_stack.h b/src/ptr_stack.h index 7a3a51c..75fc923 100644 --- a/src/ptr_stack.h +++ b/src/ptr_stack.h @@ -35,6 +35,7 @@ public: return t; } T& top() { return *m_data.back(); } + const T& top() const { return *m_data.back(); } private: std::vector m_data; From f5b09d3ec670525d69194bf38f6c161990c51edd Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 3 Mar 2011 08:34:30 +0000 Subject: [PATCH 262/295] Switched the scanner list of owned indent markers to a ptr_vector --- src/scanner.cpp | 11 ++++------- src/scanner.h | 11 ++++++----- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/scanner.cpp b/src/scanner.cpp index da89ac1..199ef25 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -14,9 +14,6 @@ namespace YAML Scanner::~Scanner() { - for(unsigned i=0;i pIndent(new IndentMarker(-1, IndentMarker::NONE)); m_indentRefs.push_back(pIndent); - m_indents.push(pIndent); + m_indents.push(&m_indentRefs.back()); } // EndStream @@ -299,8 +296,8 @@ namespace YAML // and then the indent m_indents.push(&indent); - m_indentRefs.push_back(pIndent.release()); - return m_indentRefs.back(); + m_indentRefs.push_back(pIndent); + return &m_indentRefs.back(); } // PopIndentToHere diff --git a/src/scanner.h b/src/scanner.h index f76c172..59857ed 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -12,6 +12,7 @@ #include #include #include +#include "ptr_vector.h" #include "stream.h" #include "token.h" @@ -114,16 +115,16 @@ namespace YAML Stream INPUT; // the output (tokens) - std::queue m_tokens; + std::queue m_tokens; // state info bool m_startedStream, m_endedStream; bool m_simpleKeyAllowed; bool m_canBeJSONFlow; - std::stack m_simpleKeys; - std::stack m_indents; - std::vector m_indentRefs; // for "garbage collection" - std::stack m_flows; + std::stack m_simpleKeys; + std::stack m_indents; + ptr_vector m_indentRefs; // for "garbage collection" + std::stack m_flows; }; } From 77d20873dcaad2bcbe1be35e243c3ce2c1f66fa0 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 3 Mar 2011 08:57:00 +0000 Subject: [PATCH 263/295] Removed the default --- at the start of all emitter output --- src/emitter.cpp | 10 ++-- test/emittertests.cpp | 126 +++++++++++++++++++++--------------------- 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/src/emitter.cpp b/src/emitter.cpp index d65fd0b..a60e849 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -152,8 +152,6 @@ namespace YAML switch(curState) { // document-level case ES_WAITING_FOR_DOC: - m_stream << "---"; - m_pState->RequireSoftSeparation(); m_pState->SwitchState(ES_WRITING_DOC); return true; case ES_WRITING_DOC: @@ -340,8 +338,10 @@ namespace YAML curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE || curState == ES_WRITING_DOC ) { - m_stream << "\n"; - m_pState->UnsetSeparation(); + if(m_pState->RequiresHardSeparation() || curState != ES_WRITING_DOC) { + m_stream << "\n"; + m_pState->UnsetSeparation(); + } } m_pState->PushState(ES_WAITING_FOR_BLOCK_SEQ_ENTRY); } else if(flowType == Flow) { @@ -408,7 +408,7 @@ namespace YAML curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE || curState == ES_WRITING_DOC ) { - if(m_pState->RequiresHardSeparation() || curState != ES_WRITING_BLOCK_SEQ_ENTRY) { + if(m_pState->RequiresHardSeparation() || (curState != ES_WRITING_DOC && curState != ES_WRITING_BLOCK_SEQ_ENTRY)) { m_stream << "\n"; m_pState->UnsetSeparation(); } diff --git a/test/emittertests.cpp b/test/emittertests.cpp index b4114e0..d7ee307 100644 --- a/test/emittertests.cpp +++ b/test/emittertests.cpp @@ -9,7 +9,7 @@ namespace Test void SimpleScalar(YAML::Emitter& out, std::string& desiredOutput) { out << "Hello, World!"; - desiredOutput = "--- Hello, World!"; + desiredOutput = "Hello, World!"; } void SimpleSeq(YAML::Emitter& out, std::string& desiredOutput) { @@ -19,7 +19,7 @@ namespace Test out << "milk"; out << YAML::EndSeq; - desiredOutput = "---\n- eggs\n- bread\n- milk"; + desiredOutput = "- eggs\n- bread\n- milk"; } void SimpleFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { @@ -30,7 +30,7 @@ namespace Test out << "Moe"; out << YAML::EndSeq; - desiredOutput = "--- [Larry, Curly, Moe]"; + desiredOutput = "[Larry, Curly, Moe]"; } void EmptyFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { @@ -38,7 +38,7 @@ namespace Test out << YAML::BeginSeq; out << YAML::EndSeq; - desiredOutput = "--- []"; + desiredOutput = "[]"; } void NestedBlockSeq(YAML::Emitter& out, std::string& desiredOutput) { @@ -47,7 +47,7 @@ namespace Test out << YAML::BeginSeq << "subitem 1" << "subitem 2" << YAML::EndSeq; out << YAML::EndSeq; - desiredOutput = "---\n- item 1\n-\n - subitem 1\n - subitem 2"; + desiredOutput = "- item 1\n-\n - subitem 1\n - subitem 2"; } void NestedFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { @@ -56,7 +56,7 @@ namespace Test out << YAML::Flow << YAML::BeginSeq << "two" << "three" << YAML::EndSeq; out << YAML::EndSeq; - desiredOutput = "---\n- one\n- [two, three]"; + desiredOutput = "- one\n- [two, three]"; } void SimpleMap(YAML::Emitter& out, std::string& desiredOutput) { @@ -67,7 +67,7 @@ namespace Test out << YAML::Value << "3B"; out << YAML::EndMap; - desiredOutput = "---\nname: Ryan Braun\nposition: 3B"; + desiredOutput = "name: Ryan Braun\nposition: 3B"; } void SimpleFlowMap(YAML::Emitter& out, std::string& desiredOutput) { @@ -79,7 +79,7 @@ namespace Test out << YAML::Value << "blue"; out << YAML::EndMap; - desiredOutput = "--- {shape: square, color: blue}"; + desiredOutput = "{shape: square, color: blue}"; } void MapAndList(YAML::Emitter& out, std::string& desiredOutput) { @@ -90,7 +90,7 @@ namespace Test out << YAML::Value << YAML::BeginSeq << "Sasha" << "Malia" << YAML::EndSeq; out << YAML::EndMap; - desiredOutput = "---\nname: Barack Obama\nchildren:\n - Sasha\n - Malia"; + desiredOutput = "name: Barack Obama\nchildren:\n - Sasha\n - Malia"; } void ListAndMap(YAML::Emitter& out, std::string& desiredOutput) { @@ -103,7 +103,7 @@ namespace Test out << "item 2"; out << YAML::EndSeq; - desiredOutput = "---\n- item 1\n- pens: 8\n pencils: 14\n- item 2"; + desiredOutput = "- item 1\n- pens: 8\n pencils: 14\n- item 2"; } void NestedBlockMap(YAML::Emitter& out, std::string& desiredOutput) { @@ -119,7 +119,7 @@ namespace Test out << YAML::EndMap; out << YAML::EndMap; - desiredOutput = "---\nname: Fred\ngrades:\n algebra: A\n physics: C+\n literature: B"; + desiredOutput = "name: Fred\ngrades:\n algebra: A\n physics: C+\n literature: B"; } void NestedFlowMap(YAML::Emitter& out, std::string& desiredOutput) { @@ -136,7 +136,7 @@ namespace Test out << YAML::EndMap; out << YAML::EndMap; - desiredOutput = "--- {name: Fred, grades: {algebra: A, physics: C+, literature: B}}"; + desiredOutput = "{name: Fred, grades: {algebra: A, physics: C+, literature: B}}"; } void MapListMix(YAML::Emitter& out, std::string& desiredOutput) { @@ -149,7 +149,7 @@ namespace Test out << YAML::Key << "invincible" << YAML::Value << YAML::OnOffBool << false; out << YAML::EndMap; - desiredOutput = "---\nname: Bob\nposition: [2, 4]\ninvincible: off"; + desiredOutput = "name: Bob\nposition: [2, 4]\ninvincible: off"; } void SimpleLongKey(YAML::Emitter& out, std::string& desiredOutput) @@ -162,7 +162,7 @@ namespace Test out << YAML::Value << 145; out << YAML::EndMap; - desiredOutput = "---\n? height\n: 5'9\"\n? weight\n: 145"; + desiredOutput = "? height\n: 5'9\"\n? weight\n: 145"; } void SingleLongKey(YAML::Emitter& out, std::string& desiredOutput) @@ -176,7 +176,7 @@ namespace Test out << YAML::Value << 145; out << YAML::EndMap; - desiredOutput = "---\nage: 24\n? height\n: 5'9\"\nweight: 145"; + desiredOutput = "age: 24\n? height\n: 5'9\"\nweight: 145"; } void ComplexLongKey(YAML::Emitter& out, std::string& desiredOutput) @@ -189,7 +189,7 @@ namespace Test out << YAML::Value << "demon"; out << YAML::EndMap; - desiredOutput = "---\n?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon"; + desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon"; } void AutoLongKey(YAML::Emitter& out, std::string& desiredOutput) @@ -203,7 +203,7 @@ namespace Test out << YAML::Value << "angel"; out << YAML::EndMap; - desiredOutput = "---\n?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon\nthe origin: angel"; + desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon\nthe origin: angel"; } void ScalarFormat(YAML::Emitter& out, std::string& desiredOutput) @@ -217,7 +217,7 @@ namespace Test out << YAML::Literal << "literal scalar\nthat may span\nmany, many\nlines and have \"whatever\" crazy\tsymbols that we like"; out << YAML::EndSeq; - desiredOutput = "---\n- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\x0adouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like"; + desiredOutput = "- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\x0adouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like"; } void AutoLongKeyScalar(YAML::Emitter& out, std::string& desiredOutput) @@ -227,7 +227,7 @@ namespace Test out << YAML::Value << "and its value"; out << YAML::EndMap; - desiredOutput = "---\n? |\n multi-line\n scalar\n: and its value"; + desiredOutput = "? |\n multi-line\n scalar\n: and its value"; } void LongKeyFlowMap(YAML::Emitter& out, std::string& desiredOutput) @@ -240,7 +240,7 @@ namespace Test out << YAML::Value << "and its value"; out << YAML::EndMap; - desiredOutput = "--- {simple key: and value, ? long key: and its value}"; + desiredOutput = "{simple key: and value, ? long key: and its value}"; } void BlockMapAsKey(YAML::Emitter& out, std::string& desiredOutput) @@ -255,7 +255,7 @@ namespace Test out << "total value"; out << YAML::EndMap; - desiredOutput = "---\n?\n key: value\n next key: next value\n: total value"; + desiredOutput = "?\n key: value\n next key: next value\n: total value"; } void AliasAndAnchor(YAML::Emitter& out, std::string& desiredOutput) @@ -269,7 +269,7 @@ namespace Test out << YAML::Alias("fred"); out << YAML::EndSeq; - desiredOutput = "---\n- &fred\n name: Fred\n age: 42\n- *fred"; + desiredOutput = "- &fred\n name: Fred\n age: 42\n- *fred"; } void AliasAndAnchorWithNull(YAML::Emitter& out, std::string& desiredOutput) @@ -279,14 +279,14 @@ namespace Test out << YAML::Alias("fred"); out << YAML::EndSeq; - desiredOutput = "---\n- &fred ~\n- *fred"; + desiredOutput = "- &fred ~\n- *fred"; } void SimpleVerbatimTag(YAML::Emitter& out, std::string& desiredOutput) { out << YAML::VerbatimTag("!foo") << "bar"; - desiredOutput = "--- ! bar"; + desiredOutput = "! bar"; } void VerbatimTagInBlockSeq(YAML::Emitter& out, std::string& desiredOutput) @@ -296,7 +296,7 @@ namespace Test out << "baz"; out << YAML::EndSeq; - desiredOutput = "---\n- ! bar\n- baz"; + desiredOutput = "- ! bar\n- baz"; } void VerbatimTagInFlowSeq(YAML::Emitter& out, std::string& desiredOutput) @@ -306,7 +306,7 @@ namespace Test out << "baz"; out << YAML::EndSeq; - desiredOutput = "--- [! bar, baz]"; + desiredOutput = "[! bar, baz]"; } void VerbatimTagInFlowSeqWithNull(YAML::Emitter& out, std::string& desiredOutput) @@ -316,7 +316,7 @@ namespace Test out << "baz"; out << YAML::EndSeq; - desiredOutput = "--- [! ~, baz]"; + desiredOutput = "[! ~, baz]"; } void VerbatimTagInBlockMap(YAML::Emitter& out, std::string& desiredOutput) @@ -326,7 +326,7 @@ namespace Test out << YAML::Value << YAML::VerbatimTag("!waz") << "baz"; out << YAML::EndMap; - desiredOutput = "---\n! bar: ! baz"; + desiredOutput = "! bar: ! baz"; } void VerbatimTagInFlowMap(YAML::Emitter& out, std::string& desiredOutput) @@ -336,7 +336,7 @@ namespace Test out << YAML::Value << "baz"; out << YAML::EndMap; - desiredOutput = "--- {! bar: baz}"; + desiredOutput = "{! bar: baz}"; } void VerbatimTagInFlowMapWithNull(YAML::Emitter& out, std::string& desiredOutput) @@ -346,21 +346,21 @@ namespace Test out << YAML::Value << "baz"; out << YAML::EndMap; - desiredOutput = "--- {! ~: baz}"; + desiredOutput = "{! ~: baz}"; } void VerbatimTagWithEmptySeq(YAML::Emitter& out, std::string& desiredOutput) { out << YAML::VerbatimTag("!foo") << YAML::BeginSeq << YAML::EndSeq; - desiredOutput = "--- !\n[]"; + desiredOutput = "!\n[]"; } void VerbatimTagWithEmptyMap(YAML::Emitter& out, std::string& desiredOutput) { out << YAML::VerbatimTag("!bar") << YAML::BeginMap << YAML::EndMap; - desiredOutput = "--- !\n{}"; + desiredOutput = "!\n{}"; } void VerbatimTagWithEmptySeqAndMap(YAML::Emitter& out, std::string& desiredOutput) @@ -370,7 +370,7 @@ namespace Test out << YAML::VerbatimTag("!bar") << YAML::BeginMap << YAML::EndMap; out << YAML::EndSeq; - desiredOutput = "---\n- !\n []\n- !\n {}"; + desiredOutput = "- !\n []\n- !\n {}"; } void ByKindTagWithScalar(YAML::Emitter& out, std::string& desiredOutput) @@ -381,14 +381,14 @@ namespace Test out << YAML::TagByKind << "12"; out << YAML::EndSeq; - desiredOutput = "---\n- \"12\"\n- 12\n- ! 12"; + desiredOutput = "- \"12\"\n- 12\n- ! 12"; } void LocalTagWithScalar(YAML::Emitter& out, std::string& desiredOutput) { out << YAML::LocalTag("foo") << "bar"; - desiredOutput = "--- !foo bar"; + desiredOutput = "!foo bar"; } void BadLocalTag(YAML::Emitter& out, std::string& desiredError) @@ -451,7 +451,7 @@ namespace Test out << YAML::Value << YAML::Alias("id001"); out << YAML::EndMap; - desiredOutput = "---\nreceipt: Oz-Ware Purchase Invoice\ndate: 2007-08-06\ncustomer:\n given: Dorothy\n family: Gale\nitems:\n - part_no: A4786\n descrip: Water Bucket (Filled)\n price: 1.47\n quantity: 4\n - part_no: E1628\n descrip: High Heeled \"Ruby\" Slippers\n price: 100.27\n quantity: 1\nbill-to: &id001\n street: |\n 123 Tornado Alley\n Suite 16\n city: East Westville\n state: KS\nship-to: *id001"; + desiredOutput = "receipt: Oz-Ware Purchase Invoice\ndate: 2007-08-06\ncustomer:\n given: Dorothy\n family: Gale\nitems:\n - part_no: A4786\n descrip: Water Bucket (Filled)\n price: 1.47\n quantity: 4\n - part_no: E1628\n descrip: High Heeled \"Ruby\" Slippers\n price: 100.27\n quantity: 1\nbill-to: &id001\n street: |\n 123 Tornado Alley\n Suite 16\n city: East Westville\n state: KS\nship-to: *id001"; } void STLContainers(YAML::Emitter& out, std::string& desiredOutput) @@ -471,7 +471,7 @@ namespace Test out << ages; out << YAML::EndSeq; - desiredOutput = "---\n- [2, 3, 5, 7, 11, 13]\n- Daniel: 26\n Jesse: 24"; + desiredOutput = "- [2, 3, 5, 7, 11, 13]\n- Daniel: 26\n Jesse: 24"; } void SimpleComment(YAML::Emitter& out, std::string& desiredOutput) @@ -481,7 +481,7 @@ namespace Test out << YAML::Value << "least squares" << YAML::Comment("should we change this method?"); out << YAML::EndMap; - desiredOutput = "---\nmethod: least squares # should we change this method?"; + desiredOutput = "method: least squares # should we change this method?"; } void MultiLineComment(YAML::Emitter& out, std::string& desiredOutput) @@ -491,7 +491,7 @@ namespace Test out << "item 2"; out << YAML::EndSeq; - desiredOutput = "---\n- item 1 # really really long\n # comment that couldn't possibly\n # fit on one line\n- item 2"; + desiredOutput = "- item 1 # really really long\n # comment that couldn't possibly\n # fit on one line\n- item 2"; } void ComplexComments(YAML::Emitter& out, std::string& desiredOutput) @@ -501,7 +501,7 @@ namespace Test out << YAML::Value << "value"; out << YAML::EndMap; - desiredOutput = "---\n? long key # long key\n: value"; + desiredOutput = "? long key # long key\n: value"; } void Indentation(YAML::Emitter& out, std::string& desiredOutput) @@ -514,7 +514,7 @@ namespace Test out << YAML::EndMap; out << YAML::EndSeq; - desiredOutput = "---\n- key 1: value 1\n key 2:\n - a\n - b\n - c"; + desiredOutput = "- key 1: value 1\n key 2:\n - a\n - b\n - c"; } void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) @@ -529,7 +529,7 @@ namespace Test out << YAML::EndMap; out << YAML::EndSeq; - desiredOutput = "---\n- ? key 1\n : value 1\n ? key 2\n : [a, b, c]"; + desiredOutput = "- ? key 1\n : value 1\n ? key 2\n : [a, b, c]"; } void ComplexGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) @@ -548,7 +548,7 @@ namespace Test out << YAML::EndMap; out << YAML::EndSeq; - desiredOutput = "---\n- key 1: value 1\n key 2: [a, b, c]\n- ? [1, 2]\n :\n a: b"; + desiredOutput = "- key 1: value 1\n key 2: [a, b, c]\n- ? [1, 2]\n :\n a: b"; } void Null(YAML::Emitter& out, std::string& desiredOutput) @@ -561,26 +561,26 @@ namespace Test out << YAML::EndMap; out << YAML::EndSeq; - desiredOutput = "---\n- ~\n- null value: ~\n ~: null key"; + desiredOutput = "- ~\n- null value: ~\n ~: null key"; } void EscapedUnicode(YAML::Emitter& out, std::string& desiredOutput) { out << YAML::EscapeNonAscii << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; - desiredOutput = "--- \"$ \\xa2 \\u20ac \\U00024b62\""; + desiredOutput = "\"$ \\xa2 \\u20ac \\U00024b62\""; } void Unicode(YAML::Emitter& out, std::string& desiredOutput) { out << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; - desiredOutput = "--- \x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; + desiredOutput = "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; } void DoubleQuotedUnicode(YAML::Emitter& out, std::string& desiredOutput) { out << YAML::DoubleQuoted << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; - desiredOutput = "--- \"\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2\""; + desiredOutput = "\"\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2\""; } struct Foo { @@ -606,7 +606,7 @@ namespace Test out << Foo(3, "goodbye"); out << YAML::EndSeq; - desiredOutput = "---\n- x: 5\n bar: hello\n- x: 3\n bar: goodbye"; + desiredOutput = "- x: 5\n bar: hello\n- x: 3\n bar: goodbye"; } void UserTypeInContainer(YAML::Emitter& out, std::string& desiredOutput) @@ -616,7 +616,7 @@ namespace Test fv.push_back(Foo(3, "goodbye")); out << fv; - desiredOutput = "---\n- x: 5\n bar: hello\n- x: 3\n bar: goodbye"; + desiredOutput = "- x: 5\n bar: hello\n- x: 3\n bar: goodbye"; } template @@ -637,7 +637,7 @@ namespace Test out << bar << baz; out << YAML::EndSeq; - desiredOutput = "---\n- 5\n- ~"; + desiredOutput = "- 5\n- ~"; } void PointerToUserType(YAML::Emitter& out, std::string& desiredOutput) @@ -649,13 +649,13 @@ namespace Test out << bar << baz; out << YAML::EndSeq; - desiredOutput = "---\n- x: 5\n bar: hello\n- ~"; + desiredOutput = "- x: 5\n bar: hello\n- ~"; } void NewlineAtEnd(YAML::Emitter& out, std::string& desiredOutput) { out << "Hello" << YAML::Newline << YAML::Newline; - desiredOutput = "--- Hello\n\n"; + desiredOutput = "Hello\n\n"; } void NewlineInBlockSequence(YAML::Emitter& out, std::string& desiredOutput) @@ -663,7 +663,7 @@ namespace Test out << YAML::BeginSeq; out << "a" << YAML::Newline << "b" << "c" << YAML::Newline << "d"; out << YAML::EndSeq; - desiredOutput = "---\n- a\n\n- b\n- c\n\n- d"; + desiredOutput = "- a\n\n- b\n- c\n\n- d"; } void NewlineInFlowSequence(YAML::Emitter& out, std::string& desiredOutput) @@ -671,7 +671,7 @@ namespace Test out << YAML::Flow << YAML::BeginSeq; out << "a" << YAML::Newline << "b" << "c" << YAML::Newline << "d"; out << YAML::EndSeq; - desiredOutput = "--- [a\n, b, c\n, d]"; + desiredOutput = "[a\n, b, c\n, d]"; } void NewlineInBlockMap(YAML::Emitter& out, std::string& desiredOutput) @@ -681,7 +681,7 @@ namespace Test out << YAML::Key << "b" << YAML::Newline << YAML::Value << "bar"; out << YAML::LongKey << YAML::Key << "c" << YAML::Newline << YAML::Value << "car"; out << YAML::EndMap; - desiredOutput = "---\na: foo\n\nb: bar\n? c\n\n: car"; + desiredOutput = "a: foo\n\nb: bar\n? c\n\n: car"; } void NewlineInFlowMap(YAML::Emitter& out, std::string& desiredOutput) @@ -690,7 +690,7 @@ namespace Test out << YAML::Key << "a" << YAML::Value << "foo" << YAML::Newline; out << YAML::Key << "b" << YAML::Newline << YAML::Value << "bar"; out << YAML::EndMap; - desiredOutput = "--- {a: foo\n, b\n: bar}"; + desiredOutput = "{a: foo\n, b\n: bar}"; } void LotsOfNewlines(YAML::Emitter& out, std::string& desiredOutput) @@ -706,31 +706,31 @@ namespace Test out << YAML::LongKey << YAML::Key << "f" << YAML::Newline << YAML::Value << "foo"; out << YAML::EndMap; out << YAML::EndSeq; - desiredOutput = "---\n- a\n\n-\n - b\n - c\n\n\n-\n d: e\n ? f\n\n : foo"; + desiredOutput = "- a\n\n-\n - b\n - c\n\n\n-\n d: e\n ? f\n\n : foo"; } void Binary(YAML::Emitter& out, std::string& desiredOutput) { out << YAML::Binary("Hello, World!", 13); - desiredOutput = "--- !!binary \"SGVsbG8sIFdvcmxkIQ==\""; + desiredOutput = "!!binary \"SGVsbG8sIFdvcmxkIQ==\""; } void LongBinary(YAML::Emitter& out, std::string& desiredOutput) { out << YAML::Binary("Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.\n", 270); - desiredOutput = "--- !!binary \"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4K\""; + desiredOutput = "!!binary \"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4K\""; } void EmptyBinary(YAML::Emitter& out, std::string& desiredOutput) { out << YAML::Binary("", 0); - desiredOutput = "--- !!binary \"\""; + desiredOutput = "!!binary \"\""; } void ColonAtEndOfScalar(YAML::Emitter& out, std::string& desiredOutput) { out << "a:"; - desiredOutput = "--- \"a:\""; + desiredOutput = "\"a:\""; } void ColonAsScalar(YAML::Emitter& out, std::string& desiredOutput) @@ -739,7 +739,7 @@ namespace Test out << YAML::Key << "apple" << YAML::Value << ":"; out << YAML::Key << "banana" << YAML::Value << ":"; out << YAML::EndMap; - desiredOutput = "---\napple: \":\"\nbanana: \":\""; + desiredOutput = "apple: \":\"\nbanana: \":\""; } void BoolFormatting(YAML::Emitter& out, std::string& desiredOutput) @@ -771,7 +771,7 @@ namespace Test out << YAML::ShortBool << YAML::LowerCase << false; out << YAML::EndSeq; desiredOutput = - "---\n- TRUE\n- True\n- true\n- FALSE\n- False\n- false\n" + "- TRUE\n- True\n- true\n- FALSE\n- False\n- false\n" "- YES\n- Yes\n- yes\n- NO\n- No\n- no\n" "- ON\n- On\n- on\n- OFF\n- Off\n- off\n" "- Y\n- Y\n- y\n- N\n- N\n- n"; From 5b1ca74376586fbd544ddcbb4ae6d5af6f15618c Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 3 Mar 2011 09:26:12 +0000 Subject: [PATCH 264/295] Added explicit doc start/end tokens for the emitter, and set it so that if you try to write after you've already written a full doc, it writes a doc start and continues --- include/yaml-cpp/emitter.h | 2 ++ include/yaml-cpp/emittermanip.h | 4 +++ src/emitter.cpp | 51 +++++++++++++++++++++++++++++++-- test/emittertests.cpp | 27 +++++++++++++++++ 4 files changed, 82 insertions(+), 2 deletions(-) diff --git a/include/yaml-cpp/emitter.h b/include/yaml-cpp/emitter.h index bc3a31c..0e1ca26 100644 --- a/include/yaml-cpp/emitter.h +++ b/include/yaml-cpp/emitter.h @@ -75,6 +75,8 @@ namespace YAML void PostAtomicWrite(); void EmitSeparationIfNecessary(); + void EmitBeginDoc(); + void EmitEndDoc(); void EmitBeginSeq(); void EmitEndSeq(); void EmitBeginMap(); diff --git a/include/yaml-cpp/emittermanip.h b/include/yaml-cpp/emittermanip.h index 28e88be..1dc5766 100644 --- a/include/yaml-cpp/emittermanip.h +++ b/include/yaml-cpp/emittermanip.h @@ -41,6 +41,10 @@ namespace YAML Hex, Oct, + // document manipulators + BeginDoc, + EndDoc, + // sequence manipulators BeginSeq, EndSeq, diff --git a/src/emitter.cpp b/src/emitter.cpp index a60e849..8ae2f2e 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -102,6 +102,12 @@ namespace YAML return *this; switch(value) { + case BeginDoc: + EmitBeginDoc(); + break; + case EndDoc: + EmitEndDoc(); + break; case BeginSeq: EmitBeginSeq(); break; @@ -157,8 +163,8 @@ namespace YAML case ES_WRITING_DOC: return true; case ES_DONE_WITH_DOC: - m_pState->SetError("Write called on finished document"); - return true; + EmitBeginDoc(); + return false; // block sequence case ES_WAITING_FOR_BLOCK_SEQ_ENTRY: @@ -320,6 +326,47 @@ namespace YAML m_pState->UnsetSeparation(); } + // EmitBeginDoc + void Emitter::EmitBeginDoc() + { + if(!good()) + return; + + EMITTER_STATE curState = m_pState->GetCurState(); + if(curState != ES_WAITING_FOR_DOC && curState != ES_WRITING_DOC && curState != ES_DONE_WITH_DOC) { + m_pState->SetError("Unexpected begin document"); + return; + } + + if(curState == ES_WRITING_DOC || curState == ES_DONE_WITH_DOC) + m_stream << '\n'; + m_stream << "---\n"; + + m_pState->UnsetSeparation(); + m_pState->SwitchState(ES_WAITING_FOR_DOC); + } + + // EmitEndDoc + void Emitter::EmitEndDoc() + { + if(!good()) + return; + + + EMITTER_STATE curState = m_pState->GetCurState(); + if(curState != ES_WAITING_FOR_DOC && curState != ES_WRITING_DOC && curState != ES_DONE_WITH_DOC) { + m_pState->SetError("Unexpected end document"); + return; + } + + if(curState == ES_WRITING_DOC || curState == ES_DONE_WITH_DOC) + m_stream << '\n'; + m_stream << "...\n"; + + m_pState->UnsetSeparation(); + m_pState->SwitchState(ES_WAITING_FOR_DOC); + } + // EmitBeginSeq void Emitter::EmitBeginSeq() { diff --git a/test/emittertests.cpp b/test/emittertests.cpp index d7ee307..c3e0be7 100644 --- a/test/emittertests.cpp +++ b/test/emittertests.cpp @@ -776,6 +776,28 @@ namespace Test "- ON\n- On\n- on\n- OFF\n- Off\n- off\n" "- Y\n- Y\n- y\n- N\n- N\n- n"; } + + void DocStartAndEnd(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginDoc; + out << YAML::BeginSeq << 1 << 2 << 3 << YAML::EndSeq; + out << YAML::BeginDoc; + out << "Hi there!"; + out << YAML::EndDoc; + out << YAML::EndDoc; + out << YAML::EndDoc; + out << YAML::BeginDoc; + out << YAML::VerbatimTag("foo") << "bar"; + desiredOutput = "---\n- 1\n- 2\n- 3\n---\nHi there!\n...\n...\n...\n---\n! bar"; + } + + void ImplicitDocStart(YAML::Emitter& out, std::string& desiredOutput) + { + out << "Hi"; + out << "Bye"; + out << "Oops"; + desiredOutput = "Hi\n---\nBye\n---\nOops"; + } //////////////////////////////////////////////////////////////////////////////////////////////////////// // incorrect emitting @@ -870,6 +892,7 @@ namespace Test std::string desiredOutput; test(out, desiredOutput); std::string output = out.c_str(); + std::string lastError = out.GetLastError(); if(output == desiredOutput) { try { @@ -888,6 +911,8 @@ namespace Test std::cout << output << "<<<\n"; std::cout << "Desired output:\n"; std::cout << desiredOutput << "<<<\n"; + if(!out.good()) + std::cout << "Emitter error: " << lastError << "\n"; } total++; } @@ -978,6 +1003,8 @@ namespace Test RunEmitterTest(&Emitter::ColonAtEndOfScalar, "colon at end of scalar", passed, total); RunEmitterTest(&Emitter::ColonAsScalar, "colon as scalar", passed, total); RunEmitterTest(&Emitter::BoolFormatting, "bool formatting", passed, total); + RunEmitterTest(&Emitter::DocStartAndEnd, "doc start and end", passed, total); + RunEmitterTest(&Emitter::ImplicitDocStart, "implicit doc start", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total); From cee0974abdeda5d6c0d452478794ff5109571f9a Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 3 Mar 2011 20:01:32 +0000 Subject: [PATCH 265/295] Refactored parse.cpp so that VS doesn't complain, added MinSizeRel build setting, and fixed numbering in the spec tests --- CMakeLists.txt | 1 + test/spectests.cpp | 4 ++-- util/parse.cpp | 23 +++++++++++++++-------- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 639af91..ea20cfb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,6 +113,7 @@ if(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS_RELEASE "-O2") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") set(CMAKE_CXX_FLAGS_DEBUG "-g") + set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os") # set(GCC_EXTRA_OPTIONS "") # diff --git a/test/spectests.cpp b/test/spectests.cpp index 719dea2..844939b 100644 --- a/test/spectests.cpp +++ b/test/spectests.cpp @@ -2155,8 +2155,8 @@ namespace Test { RunSpecTest(&Spec::BlockIndentationHeader, "8.2", "Block Indentation Header", passed, total); RunSpecTest(&Spec::InvalidBlockScalarIndentationIndicators, "8.3", "Invalid Block Scalar Indentation Indicators", passed, total); RunSpecTest(&Spec::ChompingFinalLineBreak, "8.4", "Chomping Final Line Break", passed, total); - RunSpecTest(&Spec::ChompingTrailingLines, "8.4", "Chomping Trailing Lines", passed, total); - RunSpecTest(&Spec::EmptyScalarChomping, "8.4", "Empty Scalar Chomping", passed, total); + RunSpecTest(&Spec::ChompingTrailingLines, "8.5", "Chomping Trailing Lines", passed, total); + RunSpecTest(&Spec::EmptyScalarChomping, "8.6", "Empty Scalar Chomping", passed, total); std::cout << "Spec tests: " << passed << "/" << total << " passed\n"; return passed == total; diff --git a/util/parse.cpp b/util/parse.cpp index 8f194f0..499dab9 100644 --- a/util/parse.cpp +++ b/util/parse.cpp @@ -34,15 +34,8 @@ public: virtual void OnMapEnd() {} }; -int main(int argc, char **argv) +void parse(std::istream& input) { - Params p = ParseArgs(argc, argv); - - std::ifstream fin; - if(argc > 1) - fin.open(argv[1]); - - std::istream& input = (argc > 1 ? fin : std::cin); try { YAML::Parser parser(input); YAML::Node doc; @@ -55,5 +48,19 @@ int main(int argc, char **argv) } catch(const YAML::Exception& e) { std::cerr << e.what() << "\n"; } +} + +int main(int argc, char **argv) +{ + Params p = ParseArgs(argc, argv); + + if(argc > 1) { + std::ifstream fin; + fin.open(argv[1]); + parse(fin); + } else { + parse(std::cin); + } + return 0; } From 1132c8df2160ac24f881e3e792877a70300d2c84 Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 4 Mar 2011 02:26:59 +0000 Subject: [PATCH 266/295] Fixed folding bug (detecting indentation, example 8.2), and clipping/stripping empty strings (example 8.6) --- src/scanscalar.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/scanscalar.cpp b/src/scanscalar.cpp index 1adc469..2a7afa9 100644 --- a/src/scanscalar.cpp +++ b/src/scanscalar.cpp @@ -143,7 +143,7 @@ namespace YAML if(!nextEmptyLine && foldedNewlineCount > 0) { scalar += std::string(foldedNewlineCount - 1, '\n'); - if(foldedNewlineStartedMoreIndented || nextMoreIndented) + if(foldedNewlineStartedMoreIndented || nextMoreIndented | !foundNonEmptyLine) scalar += "\n"; foldedNewlineCount = 0; } @@ -175,12 +175,23 @@ namespace YAML scalar.erase(pos + 1); } - if(params.chomp == STRIP || params.chomp == CLIP) { - std::size_t pos = scalar.find_last_not_of('\n'); - if(params.chomp == CLIP && pos + 1 < scalar.size()) - scalar.erase(pos + 2); - else if(params.chomp == STRIP && pos < scalar.size()) - scalar.erase(pos + 1); + switch(params.chomp) { + case CLIP: { + const std::size_t pos = scalar.find_last_not_of('\n'); + if(pos == std::string::npos) + scalar.erase(); + else if(pos + 1 < scalar.size()) + scalar.erase(pos + 2); + } break; + case STRIP: { + const std::size_t pos = scalar.find_last_not_of('\n'); + if(pos == std::string::npos) + scalar.erase(); + else if(pos < scalar.size()) + scalar.erase(pos + 1); + } break; + default: + break; } return scalar; From ddfbad6c7faebd658ab2665cb259a462570288fa Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 4 Mar 2011 04:14:08 +0000 Subject: [PATCH 267/295] Added spec tests through chapter 8, all new ones pass except 8.21, which I think is wrong --- test/spectests.cpp | 279 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+) diff --git a/test/spectests.cpp b/test/spectests.cpp index 844939b..fbf3714 100644 --- a/test/spectests.cpp +++ b/test/spectests.cpp @@ -2054,6 +2054,269 @@ namespace Test { YAML_ASSERT(doc["keep"] == "\n"); return true; } + + // 8.7 + TEST LiteralScalar() + { + std::string input = + "|\n" + " literal\n" + " \ttext\n" + "\n"; + + PARSE(doc, input); + YAML_ASSERT(doc == "literal\n\ttext\n"); + return true; + } + + // 8.8 + TEST LiteralContent() + { + std::string input = + "|\n" + " \n" + " \n" + " literal\n" + " \n" + " \n" + " text\n" + "\n" + " # Comment\n"; + + PARSE(doc, input); + YAML_ASSERT(doc == "\n\nliteral\n \n\ntext\n"); + return true; + } + + // 8.9 + TEST FoldedScalar() + { + std::string input = + ">\n" + " folded\n" + " text\n" + "\n"; + + PARSE(doc, input); + YAML_ASSERT(doc == "folded text\n"); + return true; + } + + // 8.10 + TEST FoldedLines() + { + std::string input = + ">\n" + "\n" + " folded\n" + " line\n" + "\n" + " next\n" + " line\n" + " * bullet\n" + "\n" + " * list\n" + " * lines\n" + "\n" + " last\n" + " line\n" + "\n" + "# Comment\n"; + + PARSE(doc, input); + YAML_ASSERT(doc == "\nfolded line\nnext line\n * bullet\n\n * list\n * lines\n\nlast line\n"); + return true; + } + + // 8.11 + TEST MoreIndentedLines() + { + return true; // same as 8.10 + } + + // 8.12 + TEST EmptySeparationLines() + { + return true; // same as 8.10 + } + + // 8.13 + TEST FinalEmptyLines() + { + return true; // same as 8.10 + } + + // 8.14 + TEST BlockSequence() + { + std::string input = + "block sequence:\n" + " - one\n" + " - two : three\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc["block sequence"].size() == 2); + YAML_ASSERT(doc["block sequence"][0] == "one"); + YAML_ASSERT(doc["block sequence"][1].size() == 1); + YAML_ASSERT(doc["block sequence"][1]["two"] == "three"); + return true; + } + + // 8.15 + TEST BlockSequenceEntryTypes() + { + std::string input = + "- # Empty\n" + "- |\n" + " block node\n" + "- - one # Compact\n" + " - two # sequence\n" + "- one: two # Compact mapping\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 4); + YAML_ASSERT(YAML::IsNull(doc[0])); + YAML_ASSERT(doc[1] == "block node\n"); + YAML_ASSERT(doc[2].size() == 2); + YAML_ASSERT(doc[2][0] == "one"); + YAML_ASSERT(doc[2][1] == "two"); + YAML_ASSERT(doc[3].size() == 1); + YAML_ASSERT(doc[3]["one"] == "two"); + return true; + } + + // 8.16 + TEST BlockMappings() + { + std::string input = + "block mapping:\n" + " key: value\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 1); + YAML_ASSERT(doc["block mapping"].size() == 1); + YAML_ASSERT(doc["block mapping"]["key"] == "value"); + return true; + } + + // 8.17 + TEST ExplicitBlockMappingEntries() + { + std::string input = + "? explicit key # Empty value\n" + "? |\n" + " block key\n" + ": - one # Explicit compact\n" + " - two # block value\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(IsNull(doc["explicit key"])); + YAML_ASSERT(doc["block key\n"].size() == 2); + YAML_ASSERT(doc["block key\n"][0] == "one"); + YAML_ASSERT(doc["block key\n"][1] == "two"); + return true; + } + + // 8.18 + TEST ImplicitBlockMappingEntries() + { + std::string input = + "plain key: in-line value\n" + ": # Both empty\n" + "\"quoted key\":\n" + "- entry\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc["plain key"] == "in-line value"); + YAML_ASSERT(IsNull(doc[YAML::Null])); + YAML_ASSERT(doc["quoted key"].size() == 1); + YAML_ASSERT(doc["quoted key"][0] == "entry"); + return true; + } + + // 8.19 + TEST CompactBlockMappings() + { + std::string input = + "- sun: yellow\n" + "- ? earth: blue\n" + " : moon: white\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc[0].size() == 1); + YAML_ASSERT(doc[0]["sun"] == "yellow"); + YAML_ASSERT(doc[1].size() == 1); + std::map key; + key["earth"] = "blue"; + YAML_ASSERT(doc[1][key].size() == 1); + YAML_ASSERT(doc[1][key]["moon"] == "white"); + return true; + } + + // 8.20 + TEST BlockNodeTypes() + { + std::string input = + "-\n" + " \"flow in block\"\n" + "- >\n" + " Block scalar\n" + "- !!map # Block collection\n" + " foo : bar\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 3); + YAML_ASSERT(doc[0] == "flow in block"); + YAML_ASSERT(doc[1] == "Block scalar\n"); + YAML_ASSERT(doc[2].size() == 1); + YAML_ASSERT(doc[2]["foo"] == "bar"); + return true; + } + + // 8.21 + TEST BlockScalarNodes() + { + std::string input = + "literal: |2\n" + " value\n" + "folded:\n" + " !foo\n" + " >1\n" + " value\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["literal"] == "value"); + YAML_ASSERT(doc["folded"] == "value"); + YAML_ASSERT(doc["folded"].Tag() == "!foo"); + return true; + } + + // 8.22 + TEST BlockCollectionNodes() + { + std::string input = + "sequence: !!seq\n" + "- entry\n" + "- !!seq\n" + " - nested\n" + "mapping: !!map\n" + " foo: bar\n"; + + PARSE(doc, input); + YAML_ASSERT(doc.size() == 2); + YAML_ASSERT(doc["sequence"].size() == 2); + YAML_ASSERT(doc["sequence"][0] == "entry"); + YAML_ASSERT(doc["sequence"][1].size() == 1); + YAML_ASSERT(doc["sequence"][1][0] == "nested"); + YAML_ASSERT(doc["mapping"].size() == 1); + YAML_ASSERT(doc["mapping"]["foo"] == "bar"); + return true; + } } bool RunSpecTests() @@ -2157,6 +2420,22 @@ namespace Test { RunSpecTest(&Spec::ChompingFinalLineBreak, "8.4", "Chomping Final Line Break", passed, total); RunSpecTest(&Spec::ChompingTrailingLines, "8.5", "Chomping Trailing Lines", passed, total); RunSpecTest(&Spec::EmptyScalarChomping, "8.6", "Empty Scalar Chomping", passed, total); + RunSpecTest(&Spec::LiteralScalar, "8.7", "Literal Scalar", passed, total); + RunSpecTest(&Spec::LiteralContent, "8.8", "Literal Content", passed, total); + RunSpecTest(&Spec::FoldedScalar, "8.9", "Folded Scalar", passed, total); + RunSpecTest(&Spec::FoldedLines, "8.10", "Folded Lines", passed, total); + RunSpecTest(&Spec::MoreIndentedLines, "8.11", "More Indented Lines", passed, total); + RunSpecTest(&Spec::EmptySeparationLines, "8.12", "Empty Separation Lines", passed, total); + RunSpecTest(&Spec::FinalEmptyLines, "8.13", "Final Empty Lines", passed, total); + RunSpecTest(&Spec::BlockSequence, "8.14", "Block Sequence", passed, total); + RunSpecTest(&Spec::BlockSequenceEntryTypes, "8.15", "Block Sequence Entry Types", passed, total); + RunSpecTest(&Spec::BlockMappings, "8.16", "Block Mappings", passed, total); + RunSpecTest(&Spec::ExplicitBlockMappingEntries, "8.17", "Explicit Block Mapping Entries", passed, total); + RunSpecTest(&Spec::ImplicitBlockMappingEntries, "8.18", "Implicit Block Mapping Entries", passed, total); + RunSpecTest(&Spec::CompactBlockMappings, "8.19", "Compact Block Mappings", passed, total); + RunSpecTest(&Spec::BlockNodeTypes, "8.20", "Block Node Types", passed, total); + RunSpecTest(&Spec::BlockScalarNodes, "8.21", "Block Scalar Nodes", passed, total); + RunSpecTest(&Spec::BlockCollectionNodes, "8.22", "Block Collection Nodes", passed, total); std::cout << "Spec tests: " << passed << "/" << total << " passed\n"; return passed == total; From 0f0bd2bf2da8beeecdeebecca5214bc31eb903e1 Mon Sep 17 00:00:00 2001 From: jbeder Date: Fri, 4 Mar 2011 04:19:34 +0000 Subject: [PATCH 268/295] Updated for error in spec test --- test/spectests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/spectests.cpp b/test/spectests.cpp index fbf3714..7ee7d11 100644 --- a/test/spectests.cpp +++ b/test/spectests.cpp @@ -1916,7 +1916,7 @@ namespace Test { YAML_ASSERT(doc[0] == "detected\n"); YAML_ASSERT(doc[1] == "\n\n# detected\n"); YAML_ASSERT(doc[2] == " explicit\n"); - YAML_ASSERT(doc[3] == "\t detected\n"); + YAML_ASSERT(doc[3] == "\t\ndetected\n"); return true; } From 2ad6f06df581247c0c4f30eef472ab8a3feff0a6 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 10 Mar 2011 00:23:15 +0000 Subject: [PATCH 269/295] Added newline at the end --- src/contrib/graphbuilder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/contrib/graphbuilder.cpp b/src/contrib/graphbuilder.cpp index 424b302..ab5159c 100644 --- a/src/contrib/graphbuilder.cpp +++ b/src/contrib/graphbuilder.cpp @@ -13,4 +13,4 @@ namespace YAML return NULL; } } -} \ No newline at end of file +} From 9d83747162508cbf7b9ce1d4cb3890ccc35083a5 Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 15 Mar 2011 05:49:56 +0000 Subject: [PATCH 270/295] Removed comparison/implicit conversion operators for Node, and renamed Node::Read() to Node::to() --- include/yaml-cpp/node.h | 23 +- include/yaml-cpp/nodeimpl.h | 44 +-- test/parsertests.cpp | 25 +- test/spectests.cpp | 598 ++++++++++++++++++------------------ 4 files changed, 312 insertions(+), 378 deletions(-) diff --git a/include/yaml-cpp/node.h b/include/yaml-cpp/node.h index c0fa379..17ef8e0 100644 --- a/include/yaml-cpp/node.h +++ b/include/yaml-cpp/node.h @@ -62,10 +62,7 @@ namespace YAML bool Read(T& value) const; template - const T Read() const; - - template - operator T() const; + const T to() const; template friend void operator >> (const Node& node, T& value); @@ -127,24 +124,6 @@ namespace YAML node_seq m_seqData; node_map m_mapData; }; - - // comparisons with auto-conversion - template - bool operator == (const T& value, const Node& node); - - template - bool operator == (const Node& node, const T& value); - - template - bool operator != (const T& value, const Node& node); - - template - bool operator != (const Node& node, const T& value); - - bool operator == (const char *value, const Node& node); - bool operator == (const Node& node, const char *value); - bool operator != (const char *value, const Node& node); - bool operator != (const Node& node, const char *value); } #include "yaml-cpp/nodeimpl.h" diff --git a/include/yaml-cpp/nodeimpl.h b/include/yaml-cpp/nodeimpl.h index 21dc276..d26968a 100644 --- a/include/yaml-cpp/nodeimpl.h +++ b/include/yaml-cpp/nodeimpl.h @@ -13,16 +13,11 @@ namespace YAML { // implementation of templated things template - inline const T Node::Read() const { + inline const T Node::to() const { T value; *this >> value; return value; } - - template - Node::operator T() const { - return Read(); - } template inline void operator >> (const Node& node, T& value) { @@ -77,43 +72,6 @@ namespace YAML inline const Node& Node::operator [] (const char *key) const { return GetValue(std::string(key)); } - - template - inline bool operator == (const T& value, const Node& node) { - return value == node.operator T(); - } - - template - inline bool operator == (const Node& node, const T& value) { - return value == node.operator T(); - } - - template - inline bool operator != (const T& value, const Node& node) { - return value != node.operator T(); - } - - template - inline bool operator != (const Node& node, const T& value) { - return value != node.operator T(); - } - - inline bool operator == (const char *value, const Node& node) { - return std::string(value) == node; - } - - inline bool operator == (const Node& node, const char *value) { - return std::string(value) == node; - } - - inline bool operator != (const char *value, const Node& node) { - return std::string(value) != node; - } - - inline bool operator != (const Node& node, const char *value) { - return std::string(value) != node; - } - } #endif // NODEIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/test/parsertests.cpp b/test/parsertests.cpp index 74e0801..7b4174e 100644 --- a/test/parsertests.cpp +++ b/test/parsertests.cpp @@ -132,14 +132,11 @@ namespace Test parser.GetNextDocument(doc); std::string output; - doc[0] >> output; - if(output != "eggs") + if(doc[0].to() != "eggs") return false; - doc[1] >> output; - if(output != "bread") + if(doc[1].to() != "bread") return false; - doc[2] >> output; - if(output != "milk") + if(doc[2].to() != "milk") return false; return true; @@ -626,7 +623,7 @@ namespace Test return false; if(!IsNull(doc["key"])) return false; - if(doc["just a key"] != "value") + if(doc["just a key"].to() != "value") return false; return true; @@ -647,13 +644,13 @@ namespace Test parser.GetNextDocument(doc); if(doc.size() != 4) return false; - if(doc[0] != 15) + if(doc[0].to() != 15) return false; - if(doc[1] != 0x10) + if(doc[1].to() != 0x10) return false; - if(doc[2] != 030) + if(doc[2].to() != 030) return false; - if(doc[3] != 0xffffffff) + if(doc[3].to() != 0xffffffff) return false; return true; } @@ -698,11 +695,11 @@ namespace Test YAML::Node doc; parser.GetNextDocument(doc); - if(doc["a"] != 4) + if(doc["a"].to() != 4) return false; - if(doc["b"] != 2) + if(doc["b"].to() != 2) return false; - if(doc["c"] != 3) + if(doc["c"].to() != 3) return false; return true; } diff --git a/test/spectests.cpp b/test/spectests.cpp index 7ee7d11..f3f05bc 100644 --- a/test/spectests.cpp +++ b/test/spectests.cpp @@ -56,9 +56,9 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc[0] == "Mark McGwire"); - YAML_ASSERT(doc[1] == "Sammy Sosa"); - YAML_ASSERT(doc[2] == "Ken Griffey"); + YAML_ASSERT(doc[0].to() == "Mark McGwire"); + YAML_ASSERT(doc[1].to() == "Sammy Sosa"); + YAML_ASSERT(doc[2].to() == "Ken Griffey"); return true; } @@ -71,9 +71,9 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["hr"] == "65"); - YAML_ASSERT(doc["avg"] == "0.278"); - YAML_ASSERT(doc["rbi"] == "147"); + YAML_ASSERT(doc["hr"].to() == "65"); + YAML_ASSERT(doc["avg"].to() == "0.278"); + YAML_ASSERT(doc["rbi"].to() == "147"); return true; } @@ -92,13 +92,13 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["american"].size() == 3); - YAML_ASSERT(doc["american"][0] == "Boston Red Sox"); - YAML_ASSERT(doc["american"][1] == "Detroit Tigers"); - YAML_ASSERT(doc["american"][2] == "New York Yankees"); + YAML_ASSERT(doc["american"][0].to() == "Boston Red Sox"); + YAML_ASSERT(doc["american"][1].to() == "Detroit Tigers"); + YAML_ASSERT(doc["american"][2].to() == "New York Yankees"); YAML_ASSERT(doc["national"].size() == 3); - YAML_ASSERT(doc["national"][0] == "New York Mets"); - YAML_ASSERT(doc["national"][1] == "Chicago Cubs"); - YAML_ASSERT(doc["national"][2] == "Atlanta Braves"); + YAML_ASSERT(doc["national"][0].to() == "New York Mets"); + YAML_ASSERT(doc["national"][1].to() == "Chicago Cubs"); + YAML_ASSERT(doc["national"][2].to() == "Atlanta Braves"); return true; } @@ -118,13 +118,13 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc[0].size() == 3); - YAML_ASSERT(doc[0]["name"] == "Mark McGwire"); - YAML_ASSERT(doc[0]["hr"] == "65"); - YAML_ASSERT(doc[0]["avg"] == "0.278"); + YAML_ASSERT(doc[0]["name"].to() == "Mark McGwire"); + YAML_ASSERT(doc[0]["hr"].to() == "65"); + YAML_ASSERT(doc[0]["avg"].to() == "0.278"); YAML_ASSERT(doc[1].size() == 3); - YAML_ASSERT(doc[1]["name"] == "Sammy Sosa"); - YAML_ASSERT(doc[1]["hr"] == "63"); - YAML_ASSERT(doc[1]["avg"] == "0.288"); + YAML_ASSERT(doc[1]["name"].to() == "Sammy Sosa"); + YAML_ASSERT(doc[1]["hr"].to() == "63"); + YAML_ASSERT(doc[1]["avg"].to() == "0.288"); return true; } @@ -139,17 +139,17 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); YAML_ASSERT(doc[0].size() == 3); - YAML_ASSERT(doc[0][0] == "name"); - YAML_ASSERT(doc[0][1] == "hr"); - YAML_ASSERT(doc[0][2] == "avg"); + YAML_ASSERT(doc[0][0].to() == "name"); + YAML_ASSERT(doc[0][1].to() == "hr"); + YAML_ASSERT(doc[0][2].to() == "avg"); YAML_ASSERT(doc[1].size() == 3); - YAML_ASSERT(doc[1][0] == "Mark McGwire"); - YAML_ASSERT(doc[1][1] == "65"); - YAML_ASSERT(doc[1][2] == "0.278"); + YAML_ASSERT(doc[1][0].to() == "Mark McGwire"); + YAML_ASSERT(doc[1][1].to() == "65"); + YAML_ASSERT(doc[1][2].to() == "0.278"); YAML_ASSERT(doc[2].size() == 3); - YAML_ASSERT(doc[2][0] == "Sammy Sosa"); - YAML_ASSERT(doc[2][1] == "63"); - YAML_ASSERT(doc[2][2] == "0.288"); + YAML_ASSERT(doc[2][0].to() == "Sammy Sosa"); + YAML_ASSERT(doc[2][1].to() == "63"); + YAML_ASSERT(doc[2][2].to() == "0.288"); return true; } @@ -166,11 +166,11 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["Mark McGwire"].size() == 2); - YAML_ASSERT(doc["Mark McGwire"]["hr"] == "65"); - YAML_ASSERT(doc["Mark McGwire"]["avg"] == "0.278"); + YAML_ASSERT(doc["Mark McGwire"]["hr"].to() == "65"); + YAML_ASSERT(doc["Mark McGwire"]["avg"].to() == "0.278"); YAML_ASSERT(doc["Sammy Sosa"].size() == 2); - YAML_ASSERT(doc["Sammy Sosa"]["hr"] == "63"); - YAML_ASSERT(doc["Sammy Sosa"]["avg"] == "0.288"); + YAML_ASSERT(doc["Sammy Sosa"]["hr"].to() == "63"); + YAML_ASSERT(doc["Sammy Sosa"]["avg"].to() == "0.288"); return true; } @@ -191,14 +191,14 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc[0] == "Mark McGwire"); - YAML_ASSERT(doc[1] == "Sammy Sosa"); - YAML_ASSERT(doc[2] == "Ken Griffey"); + YAML_ASSERT(doc[0].to() == "Mark McGwire"); + YAML_ASSERT(doc[1].to() == "Sammy Sosa"); + YAML_ASSERT(doc[2].to() == "Ken Griffey"); PARSE_NEXT(doc); YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc[0] == "Chicago Cubs"); - YAML_ASSERT(doc[1] == "St Louis Cardinals"); + YAML_ASSERT(doc[0].to() == "Chicago Cubs"); + YAML_ASSERT(doc[1].to() == "St Louis Cardinals"); return true; } @@ -219,15 +219,15 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["time"] == "20:03:20"); - YAML_ASSERT(doc["player"] == "Sammy Sosa"); - YAML_ASSERT(doc["action"] == "strike (miss)"); + YAML_ASSERT(doc["time"].to() == "20:03:20"); + YAML_ASSERT(doc["player"].to() == "Sammy Sosa"); + YAML_ASSERT(doc["action"].to() == "strike (miss)"); PARSE_NEXT(doc); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["time"] == "20:03:47"); - YAML_ASSERT(doc["player"] == "Sammy Sosa"); - YAML_ASSERT(doc["action"] == "grand slam"); + YAML_ASSERT(doc["time"].to() == "20:03:47"); + YAML_ASSERT(doc["player"].to() == "Sammy Sosa"); + YAML_ASSERT(doc["action"].to() == "grand slam"); return true; } @@ -247,11 +247,11 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["hr"].size() == 2); - YAML_ASSERT(doc["hr"][0] == "Mark McGwire"); - YAML_ASSERT(doc["hr"][1] == "Sammy Sosa"); + YAML_ASSERT(doc["hr"][0].to() == "Mark McGwire"); + YAML_ASSERT(doc["hr"][1].to() == "Sammy Sosa"); YAML_ASSERT(doc["rbi"].size() == 2); - YAML_ASSERT(doc["rbi"][0] == "Sammy Sosa"); - YAML_ASSERT(doc["rbi"][1] == "Ken Griffey"); + YAML_ASSERT(doc["rbi"][0].to() == "Sammy Sosa"); + YAML_ASSERT(doc["rbi"][1].to() == "Ken Griffey"); return true; } @@ -271,11 +271,11 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["hr"].size() == 2); - YAML_ASSERT(doc["hr"][0] == "Mark McGwire"); - YAML_ASSERT(doc["hr"][1] == "Sammy Sosa"); + YAML_ASSERT(doc["hr"][0].to() == "Mark McGwire"); + YAML_ASSERT(doc["hr"][1].to() == "Sammy Sosa"); YAML_ASSERT(doc["rbi"].size() == 2); - YAML_ASSERT(doc["rbi"][0] == "Sammy Sosa"); - YAML_ASSERT(doc["rbi"][1] == "Ken Griffey"); + YAML_ASSERT(doc["rbi"][0].to() == "Sammy Sosa"); + YAML_ASSERT(doc["rbi"][1].to() == "Ken Griffey"); return true; } @@ -311,11 +311,11 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc[Pair("Detroit Tigers", "Chicago cubs")].size() == 1); - YAML_ASSERT(doc[Pair("Detroit Tigers", "Chicago cubs")][0] == "2001-07-23"); + YAML_ASSERT(doc[Pair("Detroit Tigers", "Chicago cubs")][0].to() == "2001-07-23"); YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")].size() == 3); - YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][0] == "2001-07-02"); - YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][1] == "2001-08-12"); - YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][2] == "2001-08-14"); + YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][0].to() == "2001-07-02"); + YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][1].to() == "2001-08-12"); + YAML_ASSERT(doc[Pair("New York Yankees", "Atlanta Braves")][2].to() == "2001-08-14"); return true; } @@ -335,14 +335,14 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); YAML_ASSERT(doc[0].size() == 2); - YAML_ASSERT(doc[0]["item"] == "Super Hoop"); - YAML_ASSERT(doc[0]["quantity"] == 1); + YAML_ASSERT(doc[0]["item"].to() == "Super Hoop"); + YAML_ASSERT(doc[0]["quantity"].to() == 1); YAML_ASSERT(doc[1].size() == 2); - YAML_ASSERT(doc[1]["item"] == "Basketball"); - YAML_ASSERT(doc[1]["quantity"] == 4); + YAML_ASSERT(doc[1]["item"].to() == "Basketball"); + YAML_ASSERT(doc[1]["quantity"].to() == 4); YAML_ASSERT(doc[2].size() == 2); - YAML_ASSERT(doc[2]["item"] == "Big Shoes"); - YAML_ASSERT(doc[2]["quantity"] == 1); + YAML_ASSERT(doc[2]["item"].to() == "Big Shoes"); + YAML_ASSERT(doc[2]["quantity"].to() == 1); return true; } @@ -356,7 +356,7 @@ namespace Test { " // || ||__"; PARSE(doc, input); - YAML_ASSERT(doc == + YAML_ASSERT(doc.to() == "\\//||\\/||\n" "// || ||__"); return true; @@ -372,7 +372,7 @@ namespace Test { " by a knee injury."; PARSE(doc, input); - YAML_ASSERT(doc == "Mark McGwire's year was crippled by a knee injury."); + YAML_ASSERT(doc.to() == "Mark McGwire's year was crippled by a knee injury."); return true; } @@ -390,7 +390,7 @@ namespace Test { " What a year!"; PARSE(doc, input); - YAML_ASSERT(doc == + YAML_ASSERT(doc.to() == "Sammy Sosa completed another fine season with great stats.\n\n" " 63 Home Runs\n" " 0.288 Batting Average\n\n" @@ -412,9 +412,9 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["name"] == "Mark McGwire"); - YAML_ASSERT(doc["accomplishment"] == "Mark set a major league home run record in 1998.\n"); - YAML_ASSERT(doc["stats"] == "65 Home Runs\n0.278 Batting Average\n"); + YAML_ASSERT(doc["name"].to() == "Mark McGwire"); + YAML_ASSERT(doc["accomplishment"].to() == "Mark set a major league home run record in 1998.\n"); + YAML_ASSERT(doc["stats"].to() == "65 Home Runs\n0.278 Batting Average\n"); return true; } @@ -432,12 +432,12 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 6); - YAML_ASSERT(doc["unicode"] == "Sosa did fine.\xe2\x98\xba"); - YAML_ASSERT(doc["control"] == "\b1998\t1999\t2000\n"); - YAML_ASSERT(doc["hex esc"] == "\x0d\x0a is \r\n"); - YAML_ASSERT(doc["single"] == "\"Howdy!\" he cried."); - YAML_ASSERT(doc["quoted"] == " # Not a 'comment'."); - YAML_ASSERT(doc["tie-fighter"] == "|\\-*-/|"); + YAML_ASSERT(doc["unicode"].to() == "Sosa did fine.\xe2\x98\xba"); + YAML_ASSERT(doc["control"].to() == "\b1998\t1999\t2000\n"); + YAML_ASSERT(doc["hex esc"].to() == "\x0d\x0a is \r\n"); + YAML_ASSERT(doc["single"].to() == "\"Howdy!\" he cried."); + YAML_ASSERT(doc["quoted"].to() == " # Not a 'comment'."); + YAML_ASSERT(doc["tie-fighter"].to() == "|\\-*-/|"); return true; } @@ -454,8 +454,8 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["plain"] == "This unquoted scalar spans many lines."); - YAML_ASSERT(doc["quoted"] == "So does this quoted scalar.\n"); + YAML_ASSERT(doc["plain"].to() == "This unquoted scalar spans many lines."); + YAML_ASSERT(doc["quoted"].to() == "So does this quoted scalar.\n"); return true; } @@ -482,16 +482,16 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); YAML_ASSERT(doc["not-date"].Tag() == "tag:yaml.org,2002:str"); - YAML_ASSERT(doc["not-date"] == "2002-04-28"); + YAML_ASSERT(doc["not-date"].to() == "2002-04-28"); YAML_ASSERT(doc["picture"].Tag() == "tag:yaml.org,2002:binary"); - YAML_ASSERT(doc["picture"] == + YAML_ASSERT(doc["picture"].to() == "R0lGODlhDAAMAIQAAP//9/X\n" "17unp5WZmZgAAAOfn515eXv\n" "Pz7Y6OjuDg4J+fn5OTk6enp\n" "56enmleECcgggoBADs=\n" ); YAML_ASSERT(doc["application specific tag"].Tag() == "!something"); - YAML_ASSERT(doc["application specific tag"] == + YAML_ASSERT(doc["application specific tag"].to() == "The semantics of the tag\n" "above may be different for\n" "different documents." @@ -524,24 +524,24 @@ namespace Test { YAML_ASSERT(doc[0].Tag() == "tag:clarkevans.com,2002:circle"); YAML_ASSERT(doc[0].size() == 2); YAML_ASSERT(doc[0]["center"].size() == 2); - YAML_ASSERT(doc[0]["center"]["x"] == 73); - YAML_ASSERT(doc[0]["center"]["y"] == 129); - YAML_ASSERT(doc[0]["radius"] == 7); + YAML_ASSERT(doc[0]["center"]["x"].to() == 73); + YAML_ASSERT(doc[0]["center"]["y"].to() == 129); + YAML_ASSERT(doc[0]["radius"].to() == 7); YAML_ASSERT(doc[1].Tag() == "tag:clarkevans.com,2002:line"); YAML_ASSERT(doc[1].size() == 2); YAML_ASSERT(doc[1]["start"].size() == 2); - YAML_ASSERT(doc[1]["start"]["x"] == 73); - YAML_ASSERT(doc[1]["start"]["y"] == 129); + YAML_ASSERT(doc[1]["start"]["x"].to() == 73); + YAML_ASSERT(doc[1]["start"]["y"].to() == 129); YAML_ASSERT(doc[1]["finish"].size() == 2); - YAML_ASSERT(doc[1]["finish"]["x"] == 89); - YAML_ASSERT(doc[1]["finish"]["y"] == 102); + YAML_ASSERT(doc[1]["finish"]["x"].to() == 89); + YAML_ASSERT(doc[1]["finish"]["y"].to() == 102); YAML_ASSERT(doc[2].Tag() == "tag:clarkevans.com,2002:label"); YAML_ASSERT(doc[2].size() == 3); YAML_ASSERT(doc[2]["start"].size() == 2); - YAML_ASSERT(doc[2]["start"]["x"] == 73); - YAML_ASSERT(doc[2]["start"]["y"] == 129); - YAML_ASSERT(doc[2]["color"] == "0xFFEEBB"); - YAML_ASSERT(doc[2]["text"] == "Pretty vector drawing."); + YAML_ASSERT(doc[2]["start"]["x"].to() == 73); + YAML_ASSERT(doc[2]["start"]["y"].to() == 129); + YAML_ASSERT(doc[2]["color"].to() == "0xFFEEBB"); + YAML_ASSERT(doc[2]["text"].to() == "Pretty vector drawing."); return true; } @@ -582,11 +582,11 @@ namespace Test { YAML_ASSERT(doc.Tag() == "tag:yaml.org,2002:omap"); YAML_ASSERT(doc.size() == 3); YAML_ASSERT(doc[0].size() == 1); - YAML_ASSERT(doc[0]["Mark McGwire"] == 65); + YAML_ASSERT(doc[0]["Mark McGwire"].to() == 65); YAML_ASSERT(doc[1].size() == 1); - YAML_ASSERT(doc[1]["Sammy Sosa"] == 63); + YAML_ASSERT(doc[1]["Sammy Sosa"].to() == 63); YAML_ASSERT(doc[2].size() == 1); - YAML_ASSERT(doc[2]["Ken Griffey"] == 58); + YAML_ASSERT(doc[2]["Ken Griffey"].to() == 58); return true; } @@ -627,38 +627,38 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.Tag() == "tag:clarkevans.com,2002:invoice"); YAML_ASSERT(doc.size() == 8); - YAML_ASSERT(doc["invoice"] == 34843); - YAML_ASSERT(doc["date"] == "2001-01-23"); + YAML_ASSERT(doc["invoice"].to() == 34843); + YAML_ASSERT(doc["date"].to() == "2001-01-23"); YAML_ASSERT(doc["bill-to"].size() == 3); - YAML_ASSERT(doc["bill-to"]["given"] == "Chris"); - YAML_ASSERT(doc["bill-to"]["family"] == "Dumars"); + YAML_ASSERT(doc["bill-to"]["given"].to() == "Chris"); + YAML_ASSERT(doc["bill-to"]["family"].to() == "Dumars"); YAML_ASSERT(doc["bill-to"]["address"].size() == 4); - YAML_ASSERT(doc["bill-to"]["address"]["lines"] == "458 Walkman Dr.\nSuite #292\n"); - YAML_ASSERT(doc["bill-to"]["address"]["city"] == "Royal Oak"); - YAML_ASSERT(doc["bill-to"]["address"]["state"] == "MI"); - YAML_ASSERT(doc["bill-to"]["address"]["postal"] == "48046"); + YAML_ASSERT(doc["bill-to"]["address"]["lines"].to() == "458 Walkman Dr.\nSuite #292\n"); + YAML_ASSERT(doc["bill-to"]["address"]["city"].to() == "Royal Oak"); + YAML_ASSERT(doc["bill-to"]["address"]["state"].to() == "MI"); + YAML_ASSERT(doc["bill-to"]["address"]["postal"].to() == "48046"); YAML_ASSERT(doc["ship-to"].size() == 3); - YAML_ASSERT(doc["ship-to"]["given"] == "Chris"); - YAML_ASSERT(doc["ship-to"]["family"] == "Dumars"); + YAML_ASSERT(doc["ship-to"]["given"].to() == "Chris"); + YAML_ASSERT(doc["ship-to"]["family"].to() == "Dumars"); YAML_ASSERT(doc["ship-to"]["address"].size() == 4); - YAML_ASSERT(doc["ship-to"]["address"]["lines"] == "458 Walkman Dr.\nSuite #292\n"); - YAML_ASSERT(doc["ship-to"]["address"]["city"] == "Royal Oak"); - YAML_ASSERT(doc["ship-to"]["address"]["state"] == "MI"); - YAML_ASSERT(doc["ship-to"]["address"]["postal"] == "48046"); + YAML_ASSERT(doc["ship-to"]["address"]["lines"].to() == "458 Walkman Dr.\nSuite #292\n"); + YAML_ASSERT(doc["ship-to"]["address"]["city"].to() == "Royal Oak"); + YAML_ASSERT(doc["ship-to"]["address"]["state"].to() == "MI"); + YAML_ASSERT(doc["ship-to"]["address"]["postal"].to() == "48046"); YAML_ASSERT(doc["product"].size() == 2); YAML_ASSERT(doc["product"][0].size() == 4); - YAML_ASSERT(doc["product"][0]["sku"] == "BL394D"); - YAML_ASSERT(doc["product"][0]["quantity"] == 4); - YAML_ASSERT(doc["product"][0]["description"] == "Basketball"); - YAML_ASSERT(doc["product"][0]["price"] == "450.00"); + YAML_ASSERT(doc["product"][0]["sku"].to() == "BL394D"); + YAML_ASSERT(doc["product"][0]["quantity"].to() == 4); + YAML_ASSERT(doc["product"][0]["description"].to() == "Basketball"); + YAML_ASSERT(doc["product"][0]["price"].to() == "450.00"); YAML_ASSERT(doc["product"][1].size() == 4); - YAML_ASSERT(doc["product"][1]["sku"] == "BL4438H"); - YAML_ASSERT(doc["product"][1]["quantity"] == 1); - YAML_ASSERT(doc["product"][1]["description"] == "Super Hoop"); - YAML_ASSERT(doc["product"][1]["price"] == "2392.00"); - YAML_ASSERT(doc["tax"] == "251.42"); - YAML_ASSERT(doc["total"] == "4443.52"); - YAML_ASSERT(doc["comments"] == "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338."); + YAML_ASSERT(doc["product"][1]["sku"].to() == "BL4438H"); + YAML_ASSERT(doc["product"][1]["quantity"].to() == 1); + YAML_ASSERT(doc["product"][1]["description"].to() == "Super Hoop"); + YAML_ASSERT(doc["product"][1]["price"].to() == "2392.00"); + YAML_ASSERT(doc["tax"].to() == "251.42"); + YAML_ASSERT(doc["total"].to() == "4443.52"); + YAML_ASSERT(doc["comments"].to() == "Late afternoon is best. Backup contact is Nancy Billsmer @ 338-4338."); return true; } @@ -695,30 +695,30 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["Time"] == "2001-11-23 15:01:42 -5"); - YAML_ASSERT(doc["User"] == "ed"); - YAML_ASSERT(doc["Warning"] == "This is an error message for the log file"); + YAML_ASSERT(doc["Time"].to() == "2001-11-23 15:01:42 -5"); + YAML_ASSERT(doc["User"].to() == "ed"); + YAML_ASSERT(doc["Warning"].to() == "This is an error message for the log file"); PARSE_NEXT(doc); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["Time"] == "2001-11-23 15:02:31 -5"); - YAML_ASSERT(doc["User"] == "ed"); - YAML_ASSERT(doc["Warning"] == "A slightly different error message."); + YAML_ASSERT(doc["Time"].to() == "2001-11-23 15:02:31 -5"); + YAML_ASSERT(doc["User"].to() == "ed"); + YAML_ASSERT(doc["Warning"].to() == "A slightly different error message."); PARSE_NEXT(doc); YAML_ASSERT(doc.size() == 4); - YAML_ASSERT(doc["Date"] == "2001-11-23 15:03:17 -5"); - YAML_ASSERT(doc["User"] == "ed"); - YAML_ASSERT(doc["Fatal"] == "Unknown variable \"bar\""); + YAML_ASSERT(doc["Date"].to() == "2001-11-23 15:03:17 -5"); + YAML_ASSERT(doc["User"].to() == "ed"); + YAML_ASSERT(doc["Fatal"].to() == "Unknown variable \"bar\""); YAML_ASSERT(doc["Stack"].size() == 2); YAML_ASSERT(doc["Stack"][0].size() == 3); - YAML_ASSERT(doc["Stack"][0]["file"] == "TopClass.py"); - YAML_ASSERT(doc["Stack"][0]["line"] == "23"); - YAML_ASSERT(doc["Stack"][0]["code"] == "x = MoreObject(\"345\\n\")\n"); + YAML_ASSERT(doc["Stack"][0]["file"].to() == "TopClass.py"); + YAML_ASSERT(doc["Stack"][0]["line"].to() == "23"); + YAML_ASSERT(doc["Stack"][0]["code"].to() == "x = MoreObject(\"345\\n\")\n"); YAML_ASSERT(doc["Stack"][1].size() == 3); - YAML_ASSERT(doc["Stack"][1]["file"] == "MoreClass.py"); - YAML_ASSERT(doc["Stack"][1]["line"] == "58"); - YAML_ASSERT(doc["Stack"][1]["code"] == "foo = bar"); + YAML_ASSERT(doc["Stack"][1]["file"].to() == "MoreClass.py"); + YAML_ASSERT(doc["Stack"][1]["line"].to() == "58"); + YAML_ASSERT(doc["Stack"][1]["code"].to() == "foo = bar"); return true; } @@ -739,11 +739,11 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["sequence"].size() == 2); - YAML_ASSERT(doc["sequence"][0] == "one"); - YAML_ASSERT(doc["sequence"][1] == "two"); + YAML_ASSERT(doc["sequence"][0].to() == "one"); + YAML_ASSERT(doc["sequence"][1].to() == "two"); YAML_ASSERT(doc["mapping"].size() == 2); - YAML_ASSERT(doc["mapping"]["sky"] == "blue"); - YAML_ASSERT(doc["mapping"]["sea"] == "green"); + YAML_ASSERT(doc["mapping"]["sky"].to() == "blue"); + YAML_ASSERT(doc["mapping"]["sea"].to() == "green"); return true; } @@ -757,11 +757,11 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["sequence"].size() == 2); - YAML_ASSERT(doc["sequence"][0] == "one"); - YAML_ASSERT(doc["sequence"][1] == "two"); + YAML_ASSERT(doc["sequence"][0].to() == "one"); + YAML_ASSERT(doc["sequence"][1].to() == "two"); YAML_ASSERT(doc["mapping"].size() == 2); - YAML_ASSERT(doc["mapping"]["sky"] == "blue"); - YAML_ASSERT(doc["mapping"]["sea"] == "green"); + YAML_ASSERT(doc["mapping"]["sky"].to() == "blue"); + YAML_ASSERT(doc["mapping"]["sea"].to() == "green"); return true; } @@ -785,8 +785,8 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["anchored"] == "value"); // TODO: assert tag - YAML_ASSERT(doc["alias"] == "value"); + YAML_ASSERT(doc["anchored"].to() == "value"); // TODO: assert tag + YAML_ASSERT(doc["alias"].to() == "value"); return true; } @@ -803,8 +803,8 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["literal"] == "some\ntext\n"); - YAML_ASSERT(doc["folded"] == "some text\n"); + YAML_ASSERT(doc["literal"].to() == "some\ntext\n"); + YAML_ASSERT(doc["folded"].to() == "some text\n"); return true; } @@ -817,8 +817,8 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["single"] == "text"); - YAML_ASSERT(doc["double"] == "text"); + YAML_ASSERT(doc["single"].to() == "text"); + YAML_ASSERT(doc["double"].to() == "text"); return true; } @@ -834,7 +834,7 @@ namespace Test { " Line break (glyphed)\n"; PARSE(doc, input); - YAML_ASSERT(doc == "Line break (no glyph)\nLine break (glyphed)\n"); + YAML_ASSERT(doc.to() == "Line break (no glyph)\nLine break (glyphed)\n"); return true; } @@ -851,8 +851,8 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["quoted"] == "Quoted\t"); - YAML_ASSERT(doc["block"] == + YAML_ASSERT(doc["quoted"].to() == "Quoted\t"); + YAML_ASSERT(doc["block"].to() == "void main() {\n" "\tprintf(\"Hello, world!\\n\");\n" "}"); @@ -870,7 +870,7 @@ namespace Test { "\\x41 \\u0041 \\U00000041\""; PARSE(doc, input); - YAML_ASSERT(doc == "Fun with \x5C \x22 \x07 \x08 \x1B \x0C \x0A \x0D \x09 \x0B " + std::string("\x00", 1) + " \x20 \xA0 \x85 \xe2\x80\xa8 \xe2\x80\xa9 A A A"); + YAML_ASSERT(doc.to() == "Fun with \x5C \x22 \x07 \x08 \x1B \x0C \x0A \x0D \x09 \x0B " + std::string("\x00", 1) + " \x20 \xA0 \x85 \xe2\x80\xa8 \xe2\x80\xa9 A A A"); return true; } @@ -915,11 +915,11 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 1); YAML_ASSERT(doc["Not indented"].size() == 2); - YAML_ASSERT(doc["Not indented"]["By one space"] == "By four\n spaces\n"); + YAML_ASSERT(doc["Not indented"]["By one space"].to() == "By four\n spaces\n"); YAML_ASSERT(doc["Not indented"]["Flow style"].size() == 3); - YAML_ASSERT(doc["Not indented"]["Flow style"][0] == "By two"); - YAML_ASSERT(doc["Not indented"]["Flow style"][1] == "Also by two"); - YAML_ASSERT(doc["Not indented"]["Flow style"][2] == "Still by two"); + YAML_ASSERT(doc["Not indented"]["Flow style"][0].to() == "By two"); + YAML_ASSERT(doc["Not indented"]["Flow style"][1].to() == "Also by two"); + YAML_ASSERT(doc["Not indented"]["Flow style"][2].to() == "Still by two"); return true; } @@ -935,10 +935,10 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 1); YAML_ASSERT(doc["a"].size() == 2); - YAML_ASSERT(doc["a"][0] == "b"); + YAML_ASSERT(doc["a"][0].to() == "b"); YAML_ASSERT(doc["a"][1].size() == 2); - YAML_ASSERT(doc["a"][1][0] == "c"); - YAML_ASSERT(doc["a"][1][1] == "d"); + YAML_ASSERT(doc["a"][1][0].to() == "c"); + YAML_ASSERT(doc["a"][1][1].to() == "d"); return true; } @@ -953,10 +953,10 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc[0].size() == 1); - YAML_ASSERT(doc[0]["foo"] == "bar"); + YAML_ASSERT(doc[0]["foo"].to() == "bar"); YAML_ASSERT(doc[1].size() == 2); - YAML_ASSERT(doc[1][0] == "baz"); - YAML_ASSERT(doc[1][1] == "baz"); + YAML_ASSERT(doc[1][0].to() == "baz"); + YAML_ASSERT(doc[1][1].to() == "baz"); return true; } @@ -974,9 +974,9 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["plain"] == "text lines"); - YAML_ASSERT(doc["quoted"] == "text lines"); - YAML_ASSERT(doc["block"] == "text\n \tlines\n"); + YAML_ASSERT(doc["plain"].to() == "text lines"); + YAML_ASSERT(doc["quoted"].to() == "text lines"); + YAML_ASSERT(doc["block"].to() == "text\n \tlines\n"); return true; } @@ -994,8 +994,8 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["Folding"] == "Empty line\nas a line feed"); - YAML_ASSERT(doc["Chomping"] == "Clipped empty lines\n"); + YAML_ASSERT(doc["Folding"].to() == "Empty line\nas a line feed"); + YAML_ASSERT(doc["Chomping"].to() == "Clipped empty lines\n"); return true; } @@ -1012,7 +1012,7 @@ namespace Test { " space"; PARSE(doc, input); - YAML_ASSERT(doc == "trimmed\n\n\nas space"); + YAML_ASSERT(doc.to() == "trimmed\n\n\nas space"); return true; } @@ -1028,7 +1028,7 @@ namespace Test { " baz\n"; PARSE(doc, input); - YAML_ASSERT(doc == "foo \n\n\t bar\n\nbaz\n"); + YAML_ASSERT(doc.to() == "foo \n\n\t bar\n\nbaz\n"); return true; } @@ -1045,7 +1045,7 @@ namespace Test { "\""; PARSE(doc, input); - YAML_ASSERT(doc == " foo\nbar\nbaz "); + YAML_ASSERT(doc.to() == " foo\nbar\nbaz "); return true; } @@ -1058,7 +1058,7 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 1); - YAML_ASSERT(doc["key"] == "value"); + YAML_ASSERT(doc["key"].to() == "value"); return true; } @@ -1086,7 +1086,7 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 1); - YAML_ASSERT(doc["key"] == "value"); + YAML_ASSERT(doc["key"].to() == "value"); return true; } @@ -1102,8 +1102,8 @@ namespace Test { void operator >> (const YAML::Node& node, StringMap& m) { m._.clear(); for(YAML::Iterator it=node.begin();it!=node.end();++it) { - std::string key = it.first(); - std::string value = it.second(); + std::string key = it.first().to(); + std::string value = it.second().to(); m._[key] = value; } } @@ -1126,8 +1126,8 @@ namespace Test { key["last"] = "Sosa"; YAML_ASSERT(doc.size() == 1); YAML_ASSERT(doc[key].size() == 2); - YAML_ASSERT(doc[key]["hr"] == 65); - YAML_ASSERT(doc[key]["avg"] == "0.278"); + YAML_ASSERT(doc[key]["hr"].to() == 65); + YAML_ASSERT(doc[key]["avg"].to() == "0.278"); return true; } @@ -1186,7 +1186,7 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.Tag() == "tag:yaml.org,2002:str"); - YAML_ASSERT(doc == "foo"); + YAML_ASSERT(doc.to() == "foo"); return true; } @@ -1224,11 +1224,11 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.Tag() == "!foo"); - YAML_ASSERT(doc == "bar"); + YAML_ASSERT(doc.to() == "bar"); PARSE_NEXT(doc); YAML_ASSERT(doc.Tag() == "tag:example.com,2000:app/foo"); - YAML_ASSERT(doc == "bar"); + YAML_ASSERT(doc.to() == "bar"); return true; } @@ -1242,7 +1242,7 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.Tag() == "tag:example.com,2000:app/int"); - YAML_ASSERT(doc == "1 - 3"); + YAML_ASSERT(doc.to() == "1 - 3"); return true; } @@ -1256,7 +1256,7 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.Tag() == "tag:example.com,2000:app/foo"); - YAML_ASSERT(doc == "bar"); + YAML_ASSERT(doc.to() == "bar"); return true; } @@ -1274,11 +1274,11 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.Tag() == "!my-light"); - YAML_ASSERT(doc == "fluorescent"); + YAML_ASSERT(doc.to() == "fluorescent"); PARSE_NEXT(doc); YAML_ASSERT(doc.Tag() == "!my-light"); - YAML_ASSERT(doc == "green"); + YAML_ASSERT(doc.to() == "green"); return true; } @@ -1293,7 +1293,7 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 1); YAML_ASSERT(doc[0].Tag() == "tag:example.com,2000:app/foo"); - YAML_ASSERT(doc[0] == "bar"); + YAML_ASSERT(doc[0].to() == "bar"); return true; } @@ -1308,12 +1308,12 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); for(YAML::Iterator it=doc.begin();it!=doc.end();++it) { - if(it.first() == "foo") { + if(it.first().to() == "foo") { YAML_ASSERT(it.first().Tag() == "tag:yaml.org,2002:str"); YAML_ASSERT(it.second().Tag() == "tag:yaml.org,2002:str"); - YAML_ASSERT(it.second() == "bar"); - } else if(it.first() == "baz") { - YAML_ASSERT(it.second() == "foo"); + YAML_ASSERT(it.second().to() == "bar"); + } else if(it.first().to() == "baz") { + YAML_ASSERT(it.second().to() == "foo"); } else return " unknown key"; } @@ -1332,9 +1332,9 @@ namespace Test { YAML_ASSERT(doc.size() == 1); for(YAML::Iterator it=doc.begin();it!=doc.end();++it) { YAML_ASSERT(it.first().Tag() == "tag:yaml.org,2002:str"); - YAML_ASSERT(it.first() == "foo"); + YAML_ASSERT(it.first().to() == "foo"); YAML_ASSERT(it.second().Tag() == "!bar"); - YAML_ASSERT(it.second() == "baz"); + YAML_ASSERT(it.second().to() == "baz"); } return true; } @@ -1363,11 +1363,11 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); YAML_ASSERT(doc[0].Tag() == "!local"); - YAML_ASSERT(doc[0] == "foo"); + YAML_ASSERT(doc[0].to() == "foo"); YAML_ASSERT(doc[1].Tag() == "tag:yaml.org,2002:str"); - YAML_ASSERT(doc[1] == "bar"); + YAML_ASSERT(doc[1].to() == "bar"); YAML_ASSERT(doc[2].Tag() == "tag:example.com,2000:app/tag%21"); - YAML_ASSERT(doc[2] == "baz"); + YAML_ASSERT(doc[2].to() == "baz"); return true; } @@ -1411,9 +1411,9 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc[0] == "12"); // TODO: check tags. How? - YAML_ASSERT(doc[1] == 12); - YAML_ASSERT(doc[2] == "12"); + YAML_ASSERT(doc[0].to() == "12"); // TODO: check tags. How? + YAML_ASSERT(doc[1].to() == 12); + YAML_ASSERT(doc[2].to() == "12"); return true; } @@ -1426,8 +1426,8 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["First occurrence"] == "Value"); - YAML_ASSERT(doc["Second occurrence"] == "Value"); + YAML_ASSERT(doc["First occurrence"].to() == "Value"); + YAML_ASSERT(doc["Second occurrence"].to() == "Value"); return true; } @@ -1442,10 +1442,10 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 4); - YAML_ASSERT(doc["First occurrence"] == "Foo"); - YAML_ASSERT(doc["Second occurrence"] == "Foo"); - YAML_ASSERT(doc["Override anchor"] == "Bar"); - YAML_ASSERT(doc["Reuse anchor"] == "Bar"); + YAML_ASSERT(doc["First occurrence"].to() == "Foo"); + YAML_ASSERT(doc["Second occurrence"].to() == "Foo"); + YAML_ASSERT(doc["Override anchor"].to() == "Bar"); + YAML_ASSERT(doc["Reuse anchor"].to() == "Bar"); return true; } @@ -1461,12 +1461,12 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); for(YAML::Iterator it=doc.begin();it!=doc.end();++it) { - if(it.first() == "foo") { + if(it.first().to() == "foo") { YAML_ASSERT(it.second().Tag() == "tag:yaml.org,2002:str"); - YAML_ASSERT(it.second() == ""); - } else if(it.first() == "") { + YAML_ASSERT(it.second().to() == ""); + } else if(it.first().to() == "") { YAML_ASSERT(it.first().Tag() == "tag:yaml.org,2002:str"); - YAML_ASSERT(it.second() == "bar"); + YAML_ASSERT(it.second().to() == "bar"); } else return " unexpected key"; } @@ -1485,7 +1485,7 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(IsNull(doc["foo"])); - YAML_ASSERT(doc[YAML::Null] == "bar"); + YAML_ASSERT(doc[YAML::Null].to() == "bar"); return true; } @@ -1501,7 +1501,7 @@ namespace Test { YAML_ASSERT(doc.size() == 1); YAML_ASSERT(doc["implicit block key"].size() == 1); YAML_ASSERT(doc["implicit block key"][0].size() == 1); - YAML_ASSERT(doc["implicit block key"][0]["implicit flow key"] == "value"); + YAML_ASSERT(doc["implicit block key"][0]["implicit flow key"].to() == "value"); return true; } @@ -1516,7 +1516,7 @@ namespace Test { " \\ \tnon-content\""; PARSE(doc, input); - YAML_ASSERT(doc == "folded to a space,\nto a line feed, or \t \tnon-content"); + YAML_ASSERT(doc.to() == "folded to a space,\nto a line feed, or \t \tnon-content"); return true; } @@ -1530,7 +1530,7 @@ namespace Test { "\t3rd non-empty \""; PARSE(doc, input); - YAML_ASSERT(doc == " 1st non-empty\n2nd non-empty 3rd non-empty "); + YAML_ASSERT(doc.to() == " 1st non-empty\n2nd non-empty 3rd non-empty "); return true; } @@ -1540,7 +1540,7 @@ namespace Test { std::string input = " 'here''s to \"quotes\"'"; PARSE(doc, input); - YAML_ASSERT(doc == "here's to \"quotes\""); + YAML_ASSERT(doc.to() == "here's to \"quotes\""); return true; } @@ -1556,7 +1556,7 @@ namespace Test { YAML_ASSERT(doc.size() == 1); YAML_ASSERT(doc["implicit block key"].size() == 1); YAML_ASSERT(doc["implicit block key"][0].size() == 1); - YAML_ASSERT(doc["implicit block key"][0]["implicit flow key"] == "value"); + YAML_ASSERT(doc["implicit block key"][0]["implicit flow key"].to() == "value"); return true; } @@ -1570,7 +1570,7 @@ namespace Test { "\t3rd non-empty '"; PARSE(doc, input); - YAML_ASSERT(doc == " 1st non-empty\n2nd non-empty 3rd non-empty "); + YAML_ASSERT(doc.to() == " 1st non-empty\n2nd non-empty 3rd non-empty "); return true; } @@ -1593,17 +1593,17 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 6); - YAML_ASSERT(doc[0] == "::vector"); - YAML_ASSERT(doc[1] == ": - ()"); - YAML_ASSERT(doc[2] == "Up, up, and away!"); - YAML_ASSERT(doc[3] == -123); - YAML_ASSERT(doc[4] == "http://example.com/foo#bar"); + YAML_ASSERT(doc[0].to() == "::vector"); + YAML_ASSERT(doc[1].to() == ": - ()"); + YAML_ASSERT(doc[2].to() == "Up, up, and away!"); + YAML_ASSERT(doc[3].to() == -123); + YAML_ASSERT(doc[4].to() == "http://example.com/foo#bar"); YAML_ASSERT(doc[5].size() == 5); - YAML_ASSERT(doc[5][0] == "::vector"); - YAML_ASSERT(doc[5][1] == ": - ()"); - YAML_ASSERT(doc[5][2] == "Up, up, and away!"); - YAML_ASSERT(doc[5][3] == -123); - YAML_ASSERT(doc[5][4] == "http://example.com/foo#bar"); + YAML_ASSERT(doc[5][0].to() == "::vector"); + YAML_ASSERT(doc[5][1].to() == ": - ()"); + YAML_ASSERT(doc[5][2].to() == "Up, up, and away!"); + YAML_ASSERT(doc[5][3].to() == -123); + YAML_ASSERT(doc[5][4].to() == "http://example.com/foo#bar"); return true; } @@ -1619,7 +1619,7 @@ namespace Test { YAML_ASSERT(doc.size() == 1); YAML_ASSERT(doc["implicit block key"].size() == 1); YAML_ASSERT(doc["implicit block key"][0].size() == 1); - YAML_ASSERT(doc["implicit block key"][0]["implicit flow key"] == "value"); + YAML_ASSERT(doc["implicit block key"][0]["implicit flow key"].to() == "value"); return true; } @@ -1633,7 +1633,7 @@ namespace Test { "\t3rd non-empty"; PARSE(doc, input); - YAML_ASSERT(doc == "1st non-empty\n2nd non-empty 3rd non-empty"); + YAML_ASSERT(doc.to() == "1st non-empty\n2nd non-empty 3rd non-empty"); return true; } @@ -1647,11 +1647,11 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc[0].size() == 2); - YAML_ASSERT(doc[0][0] == "one"); - YAML_ASSERT(doc[0][1] == "two"); + YAML_ASSERT(doc[0][0].to() == "one"); + YAML_ASSERT(doc[0][1].to() == "two"); YAML_ASSERT(doc[1].size() == 2); - YAML_ASSERT(doc[1][0] == "three"); - YAML_ASSERT(doc[1][1] == "four"); + YAML_ASSERT(doc[1][0].to() == "three"); + YAML_ASSERT(doc[1][1].to() == "four"); return true; } @@ -1670,13 +1670,13 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 5); - YAML_ASSERT(doc[0] == "double quoted"); - YAML_ASSERT(doc[1] == "single quoted"); - YAML_ASSERT(doc[2] == "plain text"); + YAML_ASSERT(doc[0].to() == "double quoted"); + YAML_ASSERT(doc[1].to() == "single quoted"); + YAML_ASSERT(doc[2].to() == "plain text"); YAML_ASSERT(doc[3].size() == 1); - YAML_ASSERT(doc[3][0] == "nested"); + YAML_ASSERT(doc[3][0].to() == "nested"); YAML_ASSERT(doc[4].size() == 1); - YAML_ASSERT(doc[4]["single"] == "pair"); + YAML_ASSERT(doc[4]["single"].to() == "pair"); return true; } @@ -1690,11 +1690,11 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc[0].size() == 2); - YAML_ASSERT(doc[0]["one"] == "two"); - YAML_ASSERT(doc[0]["three"] == "four"); + YAML_ASSERT(doc[0]["one"].to() == "two"); + YAML_ASSERT(doc[0]["three"].to() == "four"); YAML_ASSERT(doc[1].size() == 2); - YAML_ASSERT(doc[1]["five"] == "six"); - YAML_ASSERT(doc[1]["seven"] == "eight"); + YAML_ASSERT(doc[1]["five"].to() == "six"); + YAML_ASSERT(doc[1]["seven"].to() == "eight"); return true; } @@ -1710,8 +1710,8 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["explicit"] == "entry"); - YAML_ASSERT(doc["implicit"] == "entry"); + YAML_ASSERT(doc["explicit"].to() == "entry"); + YAML_ASSERT(doc["implicit"].to() == "entry"); YAML_ASSERT(IsNull(doc[YAML::Null])); return true; } @@ -1729,10 +1729,10 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 4); - YAML_ASSERT(doc["unquoted"] == "separate"); + YAML_ASSERT(doc["unquoted"].to() == "separate"); YAML_ASSERT(IsNull(doc["http://foo.com"])); YAML_ASSERT(IsNull(doc["omitted value"])); - YAML_ASSERT(doc[YAML::Null] == "omitted key"); + YAML_ASSERT(doc[YAML::Null].to() == "omitted key"); return true; } @@ -1748,8 +1748,8 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["adjacent"] == "value"); - YAML_ASSERT(doc["readable"] == "value"); + YAML_ASSERT(doc["adjacent"].to() == "value"); + YAML_ASSERT(doc["readable"].to() == "value"); YAML_ASSERT(IsNull(doc["empty"])); return true; } @@ -1765,7 +1765,7 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 1); YAML_ASSERT(doc[0].size() == 1); - YAML_ASSERT(doc[0]["foo"] == "bar"); + YAML_ASSERT(doc[0]["foo"].to() == "bar"); return true; } @@ -1781,7 +1781,7 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 1); YAML_ASSERT(doc[0].size() == 1); - YAML_ASSERT(doc[0]["foo bar"] == "baz"); + YAML_ASSERT(doc[0]["foo bar"].to() == "baz"); return true; } @@ -1797,15 +1797,15 @@ namespace Test { YAML_ASSERT(doc.size() == 3); YAML_ASSERT(doc[0].size() == 1); YAML_ASSERT(doc[0][0].size() == 1); - YAML_ASSERT(doc[0][0]["YAML"] == "separate"); + YAML_ASSERT(doc[0][0]["YAML"].to() == "separate"); YAML_ASSERT(doc[1].size() == 1); YAML_ASSERT(doc[1][0].size() == 1); - YAML_ASSERT(doc[1][0][YAML::Null] == "empty key entry"); + YAML_ASSERT(doc[1][0][YAML::Null].to() == "empty key entry"); YAML_ASSERT(doc[2].size() == 1); YAML_ASSERT(doc[2][0].size() == 1); StringMap key; key._["JSON"] = "like"; - YAML_ASSERT(doc[2][0][key] == "adjacent"); + YAML_ASSERT(doc[2][0][key].to() == "adjacent"); return true; } @@ -1840,13 +1840,13 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 5); YAML_ASSERT(doc[0].size() == 2); - YAML_ASSERT(doc[0][0] == "a"); - YAML_ASSERT(doc[0][1] == "b"); + YAML_ASSERT(doc[0][0].to() == "a"); + YAML_ASSERT(doc[0][1].to() == "b"); YAML_ASSERT(doc[1].size() == 1); - YAML_ASSERT(doc[1]["a"] == "b"); - YAML_ASSERT(doc[2] == "a"); - YAML_ASSERT(doc[3] == 'b'); - YAML_ASSERT(doc[4] == "c"); + YAML_ASSERT(doc[1]["a"].to() == "b"); + YAML_ASSERT(doc[2].to() == "a"); + YAML_ASSERT(doc[3].to() == 'b'); + YAML_ASSERT(doc[4].to() == "c"); return true; } @@ -1863,12 +1863,12 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 5); YAML_ASSERT(doc[0].Tag() == "tag:yaml.org,2002:str"); - YAML_ASSERT(doc[0] == "a"); - YAML_ASSERT(doc[1] == 'b'); - YAML_ASSERT(doc[2] == "c"); - YAML_ASSERT(doc[3] == "c"); + YAML_ASSERT(doc[0].to() == "a"); + YAML_ASSERT(doc[1].to() == 'b'); + YAML_ASSERT(doc[2].to() == "c"); + YAML_ASSERT(doc[3].to() == "c"); YAML_ASSERT(doc[4].Tag() == "tag:yaml.org,2002:str"); - YAML_ASSERT(doc[4] == ""); + YAML_ASSERT(doc[4].to() == ""); return true; } @@ -1888,10 +1888,10 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 4); - YAML_ASSERT(doc[0] == "literal\n"); - YAML_ASSERT(doc[1] == " folded\n"); - YAML_ASSERT(doc[2] == "keep\n\n"); - YAML_ASSERT(doc[3] == " strip"); + YAML_ASSERT(doc[0].to() == "literal\n"); + YAML_ASSERT(doc[1].to() == " folded\n"); + YAML_ASSERT(doc[2].to() == "keep\n\n"); + YAML_ASSERT(doc[3].to() == " strip"); return true; } @@ -1913,10 +1913,10 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 4); - YAML_ASSERT(doc[0] == "detected\n"); - YAML_ASSERT(doc[1] == "\n\n# detected\n"); - YAML_ASSERT(doc[2] == " explicit\n"); - YAML_ASSERT(doc[3] == "\t\ndetected\n"); + YAML_ASSERT(doc[0].to() == "detected\n"); + YAML_ASSERT(doc[1].to() == "\n\n# detected\n"); + YAML_ASSERT(doc[2].to() == " explicit\n"); + YAML_ASSERT(doc[3].to() == "\t\ndetected\n"); return true; } @@ -1998,9 +1998,9 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["strip"] == "text"); - YAML_ASSERT(doc["clip"] == "text\n"); - YAML_ASSERT(doc["keep"] == "text\n"); + YAML_ASSERT(doc["strip"].to() == "text"); + YAML_ASSERT(doc["clip"].to() == "text\n"); + YAML_ASSERT(doc["keep"].to() == "text\n"); return true; } @@ -2030,9 +2030,9 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["strip"] == "# text"); - YAML_ASSERT(doc["clip"] == "# text\n"); - YAML_ASSERT(doc["keep"] == "# text\n"); + YAML_ASSERT(doc["strip"].to() == "# text"); + YAML_ASSERT(doc["clip"].to() == "# text\n"); + YAML_ASSERT(doc["keep"].to() == "# text\n"); return true; } @@ -2049,9 +2049,9 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["strip"] == ""); - YAML_ASSERT(doc["clip"] == ""); - YAML_ASSERT(doc["keep"] == "\n"); + YAML_ASSERT(doc["strip"].to() == ""); + YAML_ASSERT(doc["clip"].to() == ""); + YAML_ASSERT(doc["keep"].to() == "\n"); return true; } @@ -2065,7 +2065,7 @@ namespace Test { "\n"; PARSE(doc, input); - YAML_ASSERT(doc == "literal\n\ttext\n"); + YAML_ASSERT(doc.to() == "literal\n\ttext\n"); return true; } @@ -2084,7 +2084,7 @@ namespace Test { " # Comment\n"; PARSE(doc, input); - YAML_ASSERT(doc == "\n\nliteral\n \n\ntext\n"); + YAML_ASSERT(doc.to() == "\n\nliteral\n \n\ntext\n"); return true; } @@ -2098,7 +2098,7 @@ namespace Test { "\n"; PARSE(doc, input); - YAML_ASSERT(doc == "folded text\n"); + YAML_ASSERT(doc.to() == "folded text\n"); return true; } @@ -2124,7 +2124,7 @@ namespace Test { "# Comment\n"; PARSE(doc, input); - YAML_ASSERT(doc == "\nfolded line\nnext line\n * bullet\n\n * list\n * lines\n\nlast line\n"); + YAML_ASSERT(doc.to() == "\nfolded line\nnext line\n * bullet\n\n * list\n * lines\n\nlast line\n"); return true; } @@ -2157,9 +2157,9 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 1); YAML_ASSERT(doc["block sequence"].size() == 2); - YAML_ASSERT(doc["block sequence"][0] == "one"); + YAML_ASSERT(doc["block sequence"][0].to() == "one"); YAML_ASSERT(doc["block sequence"][1].size() == 1); - YAML_ASSERT(doc["block sequence"][1]["two"] == "three"); + YAML_ASSERT(doc["block sequence"][1]["two"].to() == "three"); return true; } @@ -2177,12 +2177,12 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 4); YAML_ASSERT(YAML::IsNull(doc[0])); - YAML_ASSERT(doc[1] == "block node\n"); + YAML_ASSERT(doc[1].to() == "block node\n"); YAML_ASSERT(doc[2].size() == 2); - YAML_ASSERT(doc[2][0] == "one"); - YAML_ASSERT(doc[2][1] == "two"); + YAML_ASSERT(doc[2][0].to() == "one"); + YAML_ASSERT(doc[2][1].to() == "two"); YAML_ASSERT(doc[3].size() == 1); - YAML_ASSERT(doc[3]["one"] == "two"); + YAML_ASSERT(doc[3]["one"].to() == "two"); return true; } @@ -2196,7 +2196,7 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 1); YAML_ASSERT(doc["block mapping"].size() == 1); - YAML_ASSERT(doc["block mapping"]["key"] == "value"); + YAML_ASSERT(doc["block mapping"]["key"].to() == "value"); return true; } @@ -2214,8 +2214,8 @@ namespace Test { YAML_ASSERT(doc.size() == 2); YAML_ASSERT(IsNull(doc["explicit key"])); YAML_ASSERT(doc["block key\n"].size() == 2); - YAML_ASSERT(doc["block key\n"][0] == "one"); - YAML_ASSERT(doc["block key\n"][1] == "two"); + YAML_ASSERT(doc["block key\n"][0].to() == "one"); + YAML_ASSERT(doc["block key\n"][1].to() == "two"); return true; } @@ -2230,10 +2230,10 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc["plain key"] == "in-line value"); + YAML_ASSERT(doc["plain key"].to() == "in-line value"); YAML_ASSERT(IsNull(doc[YAML::Null])); YAML_ASSERT(doc["quoted key"].size() == 1); - YAML_ASSERT(doc["quoted key"][0] == "entry"); + YAML_ASSERT(doc["quoted key"][0].to() == "entry"); return true; } @@ -2248,12 +2248,12 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc[0].size() == 1); - YAML_ASSERT(doc[0]["sun"] == "yellow"); + YAML_ASSERT(doc[0]["sun"].to() == "yellow"); YAML_ASSERT(doc[1].size() == 1); std::map key; key["earth"] = "blue"; YAML_ASSERT(doc[1][key].size() == 1); - YAML_ASSERT(doc[1][key]["moon"] == "white"); + YAML_ASSERT(doc[1][key]["moon"].to() == "white"); return true; } @@ -2270,10 +2270,10 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 3); - YAML_ASSERT(doc[0] == "flow in block"); - YAML_ASSERT(doc[1] == "Block scalar\n"); + YAML_ASSERT(doc[0].to() == "flow in block"); + YAML_ASSERT(doc[1].to() == "Block scalar\n"); YAML_ASSERT(doc[2].size() == 1); - YAML_ASSERT(doc[2]["foo"] == "bar"); + YAML_ASSERT(doc[2]["foo"].to() == "bar"); return true; } @@ -2290,8 +2290,8 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["literal"] == "value"); - YAML_ASSERT(doc["folded"] == "value"); + YAML_ASSERT(doc["literal"].to() == "value"); + YAML_ASSERT(doc["folded"].to() == "value"); YAML_ASSERT(doc["folded"].Tag() == "!foo"); return true; } @@ -2310,11 +2310,11 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc["sequence"].size() == 2); - YAML_ASSERT(doc["sequence"][0] == "entry"); + YAML_ASSERT(doc["sequence"][0].to() == "entry"); YAML_ASSERT(doc["sequence"][1].size() == 1); - YAML_ASSERT(doc["sequence"][1][0] == "nested"); + YAML_ASSERT(doc["sequence"][1][0].to() == "nested"); YAML_ASSERT(doc["mapping"].size() == 1); - YAML_ASSERT(doc["mapping"]["foo"] == "bar"); + YAML_ASSERT(doc["mapping"]["foo"].to() == "bar"); return true; } } From d1221b44569091d4df5c82bffe4527f06c7fb4fd Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 16 Mar 2011 01:10:57 +0000 Subject: [PATCH 271/295] Added option to disable compilation of contrib code --- CMakeLists.txt | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ea20cfb..d8a25bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,8 @@ enable_testing() ### Project options ### ## Project stuff -option(YAML_CPP_BUILD_TOOLS "Enable testing and parse tools" ON) +option(YAML_CPP_BUILD_TOOLS "Enable testing and parse tools" ON) +option(YAML_CPP_BUILD_CONTRIB "Enable contrib stuff in library" ON) ## Build options # --> General @@ -54,14 +55,25 @@ option(MSVC_STHREADED_RT "MSVC: Build with single-threaded static runtime libs ( ### ### Sources, headers, directories and libs ### -file(GLOB_RECURSE sources "src/[a-zA-Z]*.cpp") -file(GLOB_RECURSE public_headers "include/yaml-cpp/[a-zA-Z]*.h") -file(GLOB_RECURSE private_headers "src/[a-zA-Z]*.h") +file(GLOB sources "src/[a-zA-Z]*.cpp") +file(GLOB public_headers "include/yaml-cpp/[a-zA-Z]*.h") +file(GLOB private_headers "src/[a-zA-Z]*.h") + +if(YAML_CPP_BUILD_CONTRIB) + file(GLOB contrib_sources "src/contrib/[a-zA-Z]*.cpp") + file(GLOB contrib_public_headers "include/yaml-cpp/contrib/[a-zA-Z]*.h") + file(GLOB contrib_private_headers "src/contrib/[a-zA-Z]*.h") +else() + add_definitions(-DYAML_CPP_NO_CONTRIB) +endif() if(VERBOSE) message(STATUS "sources: ${sources}") message(STATUS "public_headers: ${public_headers}") message(STATUS "private_headers: ${private_headers}") + message(STATUS "contrib_sources: ${contrib_sources}") + message(STATUS "contrib_public_headers: ${contrib_public_headers}") + message(STATUS "contrib_private_headers: ${contrib_private_headers}") endif() include_directories(${YAML_CPP_SOURCE_DIR}/include) @@ -214,6 +226,9 @@ add_library(yaml-cpp ${sources} ${public_headers} ${private_headers} + ${contrib_sources} + ${contrib_public_headers} + ${contrib_private_headers} ) set_target_properties(yaml-cpp PROPERTIES @@ -242,7 +257,9 @@ endif() install(TARGETS yaml-cpp ${_INSTALL_DESTINATIONS}) install( - FILES ${public_headers} + FILES + ${public_headers} + ${contrib_public_headers} DESTINATION ${INCLUDE_INSTALL_DIR} ) From 509ba0d64059a3bb375b5cf5b263a444bc3dd0c5 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 16 Mar 2011 02:31:30 +0000 Subject: [PATCH 273/295] Marked Parser, Emitter, Node, Iterator, Mark, and Null for exporting to a DLL. It appears to work properly, although VS gives me lots of warning C4251 since I didn't export all data members of each of the above classes. It seems that it's not necessary to export those members (as long as you can't access them), and most of them are STL instances, which apparently cause lots of problems for DLLs. (For example, you simply can't export instances of std::map; see http://support.microsoft.com/kb/168958.) --- include/yaml-cpp/conversion.h | 4 ++-- include/yaml-cpp/dll.h | 28 ++++++++++++++++++++++++++++ include/yaml-cpp/emitter.h | 14 ++++++-------- include/yaml-cpp/iterator.h | 7 ++++--- include/yaml-cpp/mark.h | 4 +++- include/yaml-cpp/node.h | 7 ++++--- include/yaml-cpp/noncopyable.h | 19 ++++++++++--------- include/yaml-cpp/null.h | 8 +++++--- include/yaml-cpp/parser.h | 3 ++- src/emitter.cpp | 13 +++++++++++++ 10 files changed, 77 insertions(+), 30 deletions(-) create mode 100644 include/yaml-cpp/dll.h diff --git a/include/yaml-cpp/conversion.h b/include/yaml-cpp/conversion.h index 1036182..327f88d 100644 --- a/include/yaml-cpp/conversion.h +++ b/include/yaml-cpp/conversion.h @@ -18,8 +18,8 @@ namespace YAML return true; } - bool Convert(const std::string& input, bool& output); - bool Convert(const std::string& input, _Null& output); + YAML_CPP_API bool Convert(const std::string& input, bool& output); + YAML_CPP_API bool Convert(const std::string& input, _Null& output); template inline bool Convert(const std::string& input, T& output, typename enable_if >::type * = 0) { diff --git a/include/yaml-cpp/dll.h b/include/yaml-cpp/dll.h new file mode 100644 index 0000000..3c82c1a --- /dev/null +++ b/include/yaml-cpp/dll.h @@ -0,0 +1,28 @@ +#ifndef DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +// The following ifdef block is the standard way of creating macros which make exporting +// from a DLL simpler. All files within this DLL are compiled with the yaml_cpp_EXPORTS +// symbol defined on the command line. this symbol should not be defined on any project +// that uses this DLL. This way any other project whose source files include this file see +// YAML_CPP_API functions as being imported from a DLL, whereas this DLL sees symbols +// defined with this macro as being exported. +#undef YAML_CPP_API + +#ifdef YAML_CPP_DLL // Using or Building YAML-CPP DLL (definition defined manually) + #ifdef yaml_cpp_EXPORTS // Building YAML-CPP DLL (definition created by CMake or defined manually) + // #pragma message( "Defining YAML_CPP_API for DLL export" ) + #define YAML_CPP_API __declspec(dllexport) + #else // yaml_cpp_EXPORTS + // #pragma message( "Defining YAML_CPP_API for DLL import" ) + #define YAML_CPP_API __declspec(dllimport) + #endif // yaml_cpp_EXPORTS +#else //YAML_CPP_DLL +#define YAML_CPP_API +#endif // YAML_CPP_DLL + +#endif // DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/emitter.h b/include/yaml-cpp/emitter.h index 0e1ca26..86d3ed8 100644 --- a/include/yaml-cpp/emitter.h +++ b/include/yaml-cpp/emitter.h @@ -6,6 +6,7 @@ #endif +#include "yaml-cpp/dll.h" #include "yaml-cpp/emittermanip.h" #include "yaml-cpp/ostream.h" #include "yaml-cpp/noncopyable.h" @@ -18,7 +19,7 @@ namespace YAML { class EmitterState; - class Emitter: private noncopyable + class YAML_CPP_API Emitter: private noncopyable { public: Emitter(); @@ -65,7 +66,9 @@ namespace YAML private: void PreWriteIntegralType(std::stringstream& str); + void PreWriteStreamable(std::stringstream& str); void PostWriteIntegralType(const std::stringstream& str); + void PostWriteStreamable(const std::stringstream& str); private: enum ATOMIC_TYPE { AT_SCALAR, AT_SEQ, AT_BLOCK_SEQ, AT_FLOW_SEQ, AT_MAP, AT_BLOCK_MAP, AT_FLOW_MAP }; @@ -114,15 +117,10 @@ namespace YAML if(!good()) return *this; - PreAtomicWrite(); - EmitSeparationIfNecessary(); - std::stringstream str; - str.precision(15); + PreWriteStreamable(str); str << value; - m_stream << str.str(); - - PostAtomicWrite(); + PostWriteStreamable(str); return *this; } diff --git a/include/yaml-cpp/iterator.h b/include/yaml-cpp/iterator.h index e1d95e4..2397db9 100644 --- a/include/yaml-cpp/iterator.h +++ b/include/yaml-cpp/iterator.h @@ -5,6 +5,7 @@ #pragma once #endif +#include "yaml-cpp/dll.h" #include namespace YAML @@ -12,7 +13,7 @@ namespace YAML class Node; struct IterPriv; - class Iterator + class YAML_CPP_API Iterator { public: Iterator(); @@ -28,8 +29,8 @@ namespace YAML const Node& first() const; const Node& second() const; - friend bool operator == (const Iterator& it, const Iterator& jt); - friend bool operator != (const Iterator& it, const Iterator& jt); + friend YAML_CPP_API bool operator == (const Iterator& it, const Iterator& jt); + friend YAML_CPP_API bool operator != (const Iterator& it, const Iterator& jt); private: std::auto_ptr m_pData; diff --git a/include/yaml-cpp/mark.h b/include/yaml-cpp/mark.h index 358f251..09057da 100644 --- a/include/yaml-cpp/mark.h +++ b/include/yaml-cpp/mark.h @@ -6,9 +6,11 @@ #endif +#include "yaml-cpp/dll.h" + namespace YAML { - struct Mark { + struct YAML_CPP_API Mark { Mark(): pos(0), line(0), column(0) {} static const Mark null() { return Mark(-1, -1, -1); } diff --git a/include/yaml-cpp/node.h b/include/yaml-cpp/node.h index 17ef8e0..ff752c4 100644 --- a/include/yaml-cpp/node.h +++ b/include/yaml-cpp/node.h @@ -7,6 +7,7 @@ #include "yaml-cpp/conversion.h" +#include "yaml-cpp/dll.h" #include "yaml-cpp/exceptions.h" #include "yaml-cpp/iterator.h" #include "yaml-cpp/ltnode.h" @@ -29,7 +30,7 @@ namespace YAML struct NodeType { enum value { Null, Scalar, Sequence, Map }; }; - class Node: private noncopyable + class YAML_CPP_API Node: private noncopyable { public: friend class NodeOwnership; @@ -65,7 +66,7 @@ namespace YAML const T to() const; template - friend void operator >> (const Node& node, T& value); + friend YAML_CPP_API void operator >> (const Node& node, T& value); // retrieval for maps and sequences template @@ -82,7 +83,7 @@ namespace YAML const std::string& Tag() const { return m_tag; } // emitting - friend Emitter& operator << (Emitter& out, const Node& node); + friend YAML_CPP_API Emitter& operator << (Emitter& out, const Node& node); // ordering int Compare(const Node& rhs) const; diff --git a/include/yaml-cpp/noncopyable.h b/include/yaml-cpp/noncopyable.h index 0b056e8..1614b68 100644 --- a/include/yaml-cpp/noncopyable.h +++ b/include/yaml-cpp/noncopyable.h @@ -5,20 +5,21 @@ #pragma once #endif +#include "yaml-cpp/dll.h" namespace YAML { // this is basically boost::noncopyable - class noncopyable - { - protected: - noncopyable() {} - ~noncopyable() {} + class YAML_CPP_API noncopyable + { + protected: + noncopyable() {} + ~noncopyable() {} - private: - noncopyable(const noncopyable&); - const noncopyable& operator = (const noncopyable&); - }; + private: + noncopyable(const noncopyable&); + const noncopyable& operator = (const noncopyable&); + }; } #endif // NONCOPYABLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/null.h b/include/yaml-cpp/null.h index b430344..9c7986b 100644 --- a/include/yaml-cpp/null.h +++ b/include/yaml-cpp/null.h @@ -6,17 +6,19 @@ #endif +#include "yaml-cpp/dll.h" + namespace YAML { class Node; - struct _Null {}; + struct YAML_CPP_API _Null {}; inline bool operator == (const _Null&, const _Null&) { return true; } inline bool operator != (const _Null&, const _Null&) { return false; } - bool IsNull(const Node& node); + YAML_CPP_API bool IsNull(const Node& node); - extern _Null Null; + extern YAML_CPP_API _Null Null; } #endif // NULL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/include/yaml-cpp/parser.h b/include/yaml-cpp/parser.h index dc2ce5a..32a2d16 100644 --- a/include/yaml-cpp/parser.h +++ b/include/yaml-cpp/parser.h @@ -6,6 +6,7 @@ #endif +#include "yaml-cpp/dll.h" #include "yaml-cpp/noncopyable.h" #include #include @@ -19,7 +20,7 @@ namespace YAML class Node; class Scanner; - class Parser: private noncopyable + class YAML_CPP_API Parser: private noncopyable { public: Parser(); diff --git a/src/emitter.cpp b/src/emitter.cpp index 8ae2f2e..ad21e22 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -657,12 +657,25 @@ namespace YAML } } + void Emitter::PreWriteStreamable(std::stringstream& str) + { + PreAtomicWrite(); + EmitSeparationIfNecessary(); + str.precision(15); + } + void Emitter::PostWriteIntegralType(const std::stringstream& str) { m_stream << str.str(); PostAtomicWrite(); } + void Emitter::PostWriteStreamable(const std::stringstream& str) + { + m_stream << str.str(); + PostAtomicWrite(); + } + const char *Emitter::ComputeFullBoolName(bool b) const { const EMITTER_MANIP mainFmt = (m_pState->GetBoolLengthFormat() == ShortBool ? YesNoBool : m_pState->GetBoolFormat()); From e1f27488d13a68853bdd3e3ca4dbacb84882193d Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 17 Mar 2011 02:04:34 +0000 Subject: [PATCH 274/295] Fixed mixed line endings --- CMakeLists.txt | 40 +++++++++++++++--------------- include/yaml-cpp/dll.h | 56 +++++++++++++++++++++--------------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d8a25bf..2d62222 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,7 @@ enable_testing() ### Project options ### ## Project stuff -option(YAML_CPP_BUILD_TOOLS "Enable testing and parse tools" ON) +option(YAML_CPP_BUILD_TOOLS "Enable testing and parse tools" ON) option(YAML_CPP_BUILD_CONTRIB "Enable contrib stuff in library" ON) ## Build options @@ -118,33 +118,33 @@ if(CMAKE_COMPILER_IS_GNUCXX) endif() ### Project stuff - if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release) - endif() - # - set(CMAKE_CXX_FLAGS_RELEASE "-O2") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") - set(CMAKE_CXX_FLAGS_DEBUG "-g") - set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os") + if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) + endif() + # + set(CMAKE_CXX_FLAGS_RELEASE "-O2") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") + set(CMAKE_CXX_FLAGS_DEBUG "-g") + set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os") + # + set(GCC_EXTRA_OPTIONS "") # - set(GCC_EXTRA_OPTIONS "") - # set(FLAG_TESTED "-Wextra") check_cxx_compiler_flag(${FLAG_TESTED} FLAG_WEXTRA) if(FLAG_WEXTRA) set(GCC_EXTRA_OPTIONS "${GCC_EXTRA_OPTIONS} ${FLAG_TESTED}") endif() # - set(CMAKE_CXX_FLAGS "-Wall ${GCC_EXTRA_OPTIONS} -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}") + set(CMAKE_CXX_FLAGS "-Wall ${GCC_EXTRA_OPTIONS} -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}") # - add_custom_target(debuggable $(MAKE) clean - COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug ${CMAKE_SOURCE_DIR} - COMMENT "Adjusting settings for debug compilation" - VERBATIM) - add_custom_target(releasable $(MAKE) clean - COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Release ${CMAKE_SOURCE_DIR} - COMMENT "Adjusting settings for release compilation" - VERBATIM) + add_custom_target(debuggable $(MAKE) clean + COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug ${CMAKE_SOURCE_DIR} + COMMENT "Adjusting settings for debug compilation" + VERBATIM) + add_custom_target(releasable $(MAKE) clean + COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Release ${CMAKE_SOURCE_DIR} + COMMENT "Adjusting settings for release compilation" + VERBATIM) endif() # Microsoft VisualC++ specialities diff --git a/include/yaml-cpp/dll.h b/include/yaml-cpp/dll.h index 3c82c1a..c09cf6b 100644 --- a/include/yaml-cpp/dll.h +++ b/include/yaml-cpp/dll.h @@ -1,28 +1,28 @@ -#ifndef DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#define DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 - -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 -#pragma once -#endif - -// The following ifdef block is the standard way of creating macros which make exporting -// from a DLL simpler. All files within this DLL are compiled with the yaml_cpp_EXPORTS -// symbol defined on the command line. this symbol should not be defined on any project -// that uses this DLL. This way any other project whose source files include this file see -// YAML_CPP_API functions as being imported from a DLL, whereas this DLL sees symbols -// defined with this macro as being exported. -#undef YAML_CPP_API - -#ifdef YAML_CPP_DLL // Using or Building YAML-CPP DLL (definition defined manually) - #ifdef yaml_cpp_EXPORTS // Building YAML-CPP DLL (definition created by CMake or defined manually) - // #pragma message( "Defining YAML_CPP_API for DLL export" ) - #define YAML_CPP_API __declspec(dllexport) - #else // yaml_cpp_EXPORTS - // #pragma message( "Defining YAML_CPP_API for DLL import" ) - #define YAML_CPP_API __declspec(dllimport) - #endif // yaml_cpp_EXPORTS -#else //YAML_CPP_DLL -#define YAML_CPP_API -#endif // YAML_CPP_DLL - -#endif // DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#ifndef DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +// The following ifdef block is the standard way of creating macros which make exporting +// from a DLL simpler. All files within this DLL are compiled with the yaml_cpp_EXPORTS +// symbol defined on the command line. this symbol should not be defined on any project +// that uses this DLL. This way any other project whose source files include this file see +// YAML_CPP_API functions as being imported from a DLL, whereas this DLL sees symbols +// defined with this macro as being exported. +#undef YAML_CPP_API + +#ifdef YAML_CPP_DLL // Using or Building YAML-CPP DLL (definition defined manually) + #ifdef yaml_cpp_EXPORTS // Building YAML-CPP DLL (definition created by CMake or defined manually) + // #pragma message( "Defining YAML_CPP_API for DLL export" ) + #define YAML_CPP_API __declspec(dllexport) + #else // yaml_cpp_EXPORTS + // #pragma message( "Defining YAML_CPP_API for DLL import" ) + #define YAML_CPP_API __declspec(dllimport) + #endif // yaml_cpp_EXPORTS +#else //YAML_CPP_DLL +#define YAML_CPP_API +#endif // YAML_CPP_DLL + +#endif // DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 From e468dd7d38ca15668ac9974a0d33892e8ba3cdfd Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 17 Mar 2011 02:06:10 +0000 Subject: [PATCH 275/295] Added eol-style=native prop to missing files --- CMakeLists.txt | 558 ++++++++++++++++++++++++------------------------- license.txt | 36 ++-- 2 files changed, 297 insertions(+), 297 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d62222..634d16e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,279 +1,279 @@ -### -### CMake settings -### -## Due to Mac OSX we need to keep compatibility with CMake 2.6 -# see http://www.cmake.org/Wiki/CMake_Policies -cmake_minimum_required(VERSION 2.6) -# see http://www.cmake.org/cmake/help/cmake-2-8-docs.html#policy:CMP0012 -if(POLICY CMP0012) - cmake_policy(SET CMP0012 OLD) -endif() -# see http://www.cmake.org/cmake/help/cmake-2-8-docs.html#policy:CMP0015 -if(POLICY CMP0015) - cmake_policy(SET CMP0015 OLD) -endif() - -include(CheckCXXCompilerFlag) - - -### -### Project settings -### -project(YAML_CPP) - -set(YAML_CPP_VERSION_MAJOR "0") -set(YAML_CPP_VERSION_MINOR "2") -set(YAML_CPP_VERSION_PATCH "5") -set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}") - -enable_testing() - - -### -### Project options -### -## Project stuff -option(YAML_CPP_BUILD_TOOLS "Enable testing and parse tools" ON) -option(YAML_CPP_BUILD_CONTRIB "Enable contrib stuff in library" ON) - -## Build options -# --> General -# see http://www.cmake.org/cmake/help/cmake2.6docs.html#variable:BUILD_SHARED_LIBS -# http://www.cmake.org/cmake/help/cmake2.6docs.html#command:add_library -option(BUILD_SHARED_LIBS "Build Shared Libraries" OFF) - -# --> Apple -option(APPLE_UNIVERSAL_BIN "Apple: Build universal binary" OFF) - -# --> Microsoft Visual C++ -# see http://msdn.microsoft.com/en-us/library/aa278396(v=VS.60).aspx -# http://msdn.microsoft.com/en-us/library/2kzt1wy3(v=VS.71).aspx -option(MSVC_SHARED_RT "MSVC: Build with shared runtime libs (/MD)" ON) -option(MSVC_STHREADED_RT "MSVC: Build with single-threaded static runtime libs (/ML until VS .NET 2003)" OFF) - - -### -### Sources, headers, directories and libs -### -file(GLOB sources "src/[a-zA-Z]*.cpp") -file(GLOB public_headers "include/yaml-cpp/[a-zA-Z]*.h") -file(GLOB private_headers "src/[a-zA-Z]*.h") - -if(YAML_CPP_BUILD_CONTRIB) - file(GLOB contrib_sources "src/contrib/[a-zA-Z]*.cpp") - file(GLOB contrib_public_headers "include/yaml-cpp/contrib/[a-zA-Z]*.h") - file(GLOB contrib_private_headers "src/contrib/[a-zA-Z]*.h") -else() - add_definitions(-DYAML_CPP_NO_CONTRIB) -endif() - -if(VERBOSE) - message(STATUS "sources: ${sources}") - message(STATUS "public_headers: ${public_headers}") - message(STATUS "private_headers: ${private_headers}") - message(STATUS "contrib_sources: ${contrib_sources}") - message(STATUS "contrib_public_headers: ${contrib_public_headers}") - message(STATUS "contrib_private_headers: ${contrib_private_headers}") -endif() - -include_directories(${YAML_CPP_SOURCE_DIR}/include) - - -### -### General compilation settings -### -if(BUILD_SHARED_LIBS) - set(LABEL_SUFFIX "shared") -else() - set(LABEL_SUFFIX "static") -endif() - -if(APPLE) - if(APPLE_UNIVERSAL_BIN) - set(CMAKE_OSX_ARCHITECTURES ppc;i386) - endif() -endif() - -if(IPHONE) - set(CMAKE_OSX_SYSROOT "iphoneos4.2") - set(CMAKE_OSX_ARCHITECTURES "armv6;armv7") -endif() - -if(WIN32) - if(BUILD_SHARED_LIBS) - add_definitions(-D${PROJECT_NAME}_DLL) # use or build Windows DLL - endif() - if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "C:/") - endif() -endif() - -# GCC specialities -if(CMAKE_COMPILER_IS_GNUCXX) - ### General stuff - if(WIN32) - set(CMAKE_SHARED_LIBRARY_PREFIX "") # DLLs do not have a "lib" prefix - set(CMAKE_IMPORT_LIBRARY_PREFIX "") # same for DLL import libs - set(CMAKE_LINK_DEF_FILE_FLAG "") # CMake workaround (2.8.3) - endif() - - ### Project stuff - if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release) - endif() - # - set(CMAKE_CXX_FLAGS_RELEASE "-O2") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") - set(CMAKE_CXX_FLAGS_DEBUG "-g") - set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os") - # - set(GCC_EXTRA_OPTIONS "") - # - set(FLAG_TESTED "-Wextra") - check_cxx_compiler_flag(${FLAG_TESTED} FLAG_WEXTRA) - if(FLAG_WEXTRA) - set(GCC_EXTRA_OPTIONS "${GCC_EXTRA_OPTIONS} ${FLAG_TESTED}") - endif() - # - set(CMAKE_CXX_FLAGS "-Wall ${GCC_EXTRA_OPTIONS} -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}") - # - add_custom_target(debuggable $(MAKE) clean - COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug ${CMAKE_SOURCE_DIR} - COMMENT "Adjusting settings for debug compilation" - VERBATIM) - add_custom_target(releasable $(MAKE) clean - COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Release ${CMAKE_SOURCE_DIR} - COMMENT "Adjusting settings for release compilation" - VERBATIM) -endif() - -# Microsoft VisualC++ specialities -if(MSVC) - ### General stuff - # a) Change MSVC runtime library settings (/MD[d], /MT[d], /ML[d] (single-threaded until VS 2003)) - # plus set lib suffix for later use and project label accordingly - # see http://msdn.microsoft.com/en-us/library/aa278396(v=VS.60).aspx - # http://msdn.microsoft.com/en-us/library/2kzt1wy3(v=VS.71).aspx - set(LIB_RT_SUFFIX "md") # CMake defaults to /MD for MSVC - set(LIB_RT_OPTION "/MD") - # - if(NOT MSVC_SHARED_RT) # User wants to have static runtime libraries (/MT, /ML) - if(MSVC_STHREADED_RT) # User wants to have old single-threaded static runtime libraries - set(LIB_RT_SUFFIX "ml") - set(LIB_RT_OPTION "/ML") - if(NOT ${MSVC_VERSION} LESS 1400) - message(FATAL_ERROR "Single-threaded static runtime libraries (/ML) only available until VS .NET 2003 (7.1).") - endif() - else() - set(LIB_RT_SUFFIX "mt") - set(LIB_RT_OPTION "/MT") - endif() - - # correct linker options - foreach(flag_var CMAKE_C_FLAGS CMAKE_CXX_FLAGS) - foreach(config_name "" DEBUG RELEASE MINSIZEREL RELWITHDEBINFO) - set(var_name "${flag_var}") - if(NOT "${config_name}" STREQUAL "") - set(var_name "${var_name}_${config_name}") - endif() - string(REPLACE "/MD" "${LIB_RT_OPTION}" ${var_name} "${${var_name}}") - endforeach() - endforeach() - endif() - # - set(LABEL_SUFFIX "${LABEL_SUFFIX} ${LIB_RT_OPTION}") - - # b) Change prefix for static libraries - set(CMAKE_STATIC_LIBRARY_PREFIX "lib") # to distinguish static libraries from DLL import libs - - # c) Correct suffixes for static libraries - if(NOT BUILD_SHARED_LIBS) - ### General stuff - set(LIB_TARGET_SUFFIX "${LIB_SUFFIX}${LIB_RT_SUFFIX}") - endif() - - ### Project stuff - # /W3 = set warning level; see http://msdn.microsoft.com/en-us/library/thxezb7y.aspx - # /wd4127 = disable warning C4127 "conditional expression is constant"; see http://msdn.microsoft.com/en-us/library/6t66728h.aspx - # /wd4355 = disable warning C4355 "'this' : used in base member initializer list"; http://msdn.microsoft.com/en-us/library/3c594ae3.aspx - set(CMAKE_CXX_FLAGS "/W3 /wd4127 /wd4355 /D_SCL_SECURE_NO_WARNINGS ${CMAKE_CXX_FLAGS}") -endif() - - -### -### General install settings -### -if(WIN32) - set(_library_dir bin) # .dll are in PATH, like executables -else() - set(_library_dir lib) -endif() - -set(INCLUDE_INSTALL_DIR include/yaml-cpp) -set(LIB_INSTALL_DIR "${_library_dir}${LIB_SUFFIX}") - -set(_INSTALL_DESTINATIONS - RUNTIME DESTINATION bin - LIBRARY DESTINATION ${LIB_INSTALL_DIR} - ARCHIVE DESTINATION "lib${LIB_SUFFIX}" -) - - -### -### Library -### -add_library(yaml-cpp - ${sources} - ${public_headers} - ${private_headers} - ${contrib_sources} - ${contrib_public_headers} - ${contrib_private_headers} -) - -set_target_properties(yaml-cpp PROPERTIES - VERSION "${YAML_CPP_VERSION}" - SOVERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}" - PROJECT_LABEL "yaml-cpp ${LABEL_SUFFIX}" -) - -if(IPHONE) - set_target_properties(yaml-cpp PROPERTIES - XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "3.0" - ) -endif() - -if(MSVC) - if(NOT BUILD_SHARED_LIBS) - # correct library names - set_target_properties(yaml-cpp PROPERTIES - DEBUG_POSTFIX "${LIB_TARGET_SUFFIX}d" - RELEASE_POSTFIX "${LIB_TARGET_SUFFIX}" - MINSIZEREL_POSTFIX "${LIB_TARGET_SUFFIX}" - RELWITHDEBINFO_POSTFIX "${LIB_TARGET_SUFFIX}" - ) - endif() -endif() - -install(TARGETS yaml-cpp ${_INSTALL_DESTINATIONS}) -install( - FILES - ${public_headers} - ${contrib_public_headers} - DESTINATION ${INCLUDE_INSTALL_DIR} -) - -if(UNIX) - set(PC_FILE ${CMAKE_BINARY_DIR}/yaml-cpp.pc) - configure_file("yaml-cpp.pc.cmake" ${PC_FILE} @ONLY) - install(FILES ${PC_FILE} DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) -endif() - - -### -### Extras -### -if(YAML_CPP_BUILD_TOOLS) - add_subdirectory(test) - add_subdirectory(util) -endif() +### +### CMake settings +### +## Due to Mac OSX we need to keep compatibility with CMake 2.6 +# see http://www.cmake.org/Wiki/CMake_Policies +cmake_minimum_required(VERSION 2.6) +# see http://www.cmake.org/cmake/help/cmake-2-8-docs.html#policy:CMP0012 +if(POLICY CMP0012) + cmake_policy(SET CMP0012 OLD) +endif() +# see http://www.cmake.org/cmake/help/cmake-2-8-docs.html#policy:CMP0015 +if(POLICY CMP0015) + cmake_policy(SET CMP0015 OLD) +endif() + +include(CheckCXXCompilerFlag) + + +### +### Project settings +### +project(YAML_CPP) + +set(YAML_CPP_VERSION_MAJOR "0") +set(YAML_CPP_VERSION_MINOR "2") +set(YAML_CPP_VERSION_PATCH "5") +set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}") + +enable_testing() + + +### +### Project options +### +## Project stuff +option(YAML_CPP_BUILD_TOOLS "Enable testing and parse tools" ON) +option(YAML_CPP_BUILD_CONTRIB "Enable contrib stuff in library" ON) + +## Build options +# --> General +# see http://www.cmake.org/cmake/help/cmake2.6docs.html#variable:BUILD_SHARED_LIBS +# http://www.cmake.org/cmake/help/cmake2.6docs.html#command:add_library +option(BUILD_SHARED_LIBS "Build Shared Libraries" OFF) + +# --> Apple +option(APPLE_UNIVERSAL_BIN "Apple: Build universal binary" OFF) + +# --> Microsoft Visual C++ +# see http://msdn.microsoft.com/en-us/library/aa278396(v=VS.60).aspx +# http://msdn.microsoft.com/en-us/library/2kzt1wy3(v=VS.71).aspx +option(MSVC_SHARED_RT "MSVC: Build with shared runtime libs (/MD)" ON) +option(MSVC_STHREADED_RT "MSVC: Build with single-threaded static runtime libs (/ML until VS .NET 2003)" OFF) + + +### +### Sources, headers, directories and libs +### +file(GLOB sources "src/[a-zA-Z]*.cpp") +file(GLOB public_headers "include/yaml-cpp/[a-zA-Z]*.h") +file(GLOB private_headers "src/[a-zA-Z]*.h") + +if(YAML_CPP_BUILD_CONTRIB) + file(GLOB contrib_sources "src/contrib/[a-zA-Z]*.cpp") + file(GLOB contrib_public_headers "include/yaml-cpp/contrib/[a-zA-Z]*.h") + file(GLOB contrib_private_headers "src/contrib/[a-zA-Z]*.h") +else() + add_definitions(-DYAML_CPP_NO_CONTRIB) +endif() + +if(VERBOSE) + message(STATUS "sources: ${sources}") + message(STATUS "public_headers: ${public_headers}") + message(STATUS "private_headers: ${private_headers}") + message(STATUS "contrib_sources: ${contrib_sources}") + message(STATUS "contrib_public_headers: ${contrib_public_headers}") + message(STATUS "contrib_private_headers: ${contrib_private_headers}") +endif() + +include_directories(${YAML_CPP_SOURCE_DIR}/include) + + +### +### General compilation settings +### +if(BUILD_SHARED_LIBS) + set(LABEL_SUFFIX "shared") +else() + set(LABEL_SUFFIX "static") +endif() + +if(APPLE) + if(APPLE_UNIVERSAL_BIN) + set(CMAKE_OSX_ARCHITECTURES ppc;i386) + endif() +endif() + +if(IPHONE) + set(CMAKE_OSX_SYSROOT "iphoneos4.2") + set(CMAKE_OSX_ARCHITECTURES "armv6;armv7") +endif() + +if(WIN32) + if(BUILD_SHARED_LIBS) + add_definitions(-D${PROJECT_NAME}_DLL) # use or build Windows DLL + endif() + if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "C:/") + endif() +endif() + +# GCC specialities +if(CMAKE_COMPILER_IS_GNUCXX) + ### General stuff + if(WIN32) + set(CMAKE_SHARED_LIBRARY_PREFIX "") # DLLs do not have a "lib" prefix + set(CMAKE_IMPORT_LIBRARY_PREFIX "") # same for DLL import libs + set(CMAKE_LINK_DEF_FILE_FLAG "") # CMake workaround (2.8.3) + endif() + + ### Project stuff + if(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) + endif() + # + set(CMAKE_CXX_FLAGS_RELEASE "-O2") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g") + set(CMAKE_CXX_FLAGS_DEBUG "-g") + set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os") + # + set(GCC_EXTRA_OPTIONS "") + # + set(FLAG_TESTED "-Wextra") + check_cxx_compiler_flag(${FLAG_TESTED} FLAG_WEXTRA) + if(FLAG_WEXTRA) + set(GCC_EXTRA_OPTIONS "${GCC_EXTRA_OPTIONS} ${FLAG_TESTED}") + endif() + # + set(CMAKE_CXX_FLAGS "-Wall ${GCC_EXTRA_OPTIONS} -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}") + # + add_custom_target(debuggable $(MAKE) clean + COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Debug ${CMAKE_SOURCE_DIR} + COMMENT "Adjusting settings for debug compilation" + VERBATIM) + add_custom_target(releasable $(MAKE) clean + COMMAND ${CMAKE_COMMAND} -DCMAKE_BUILD_TYPE=Release ${CMAKE_SOURCE_DIR} + COMMENT "Adjusting settings for release compilation" + VERBATIM) +endif() + +# Microsoft VisualC++ specialities +if(MSVC) + ### General stuff + # a) Change MSVC runtime library settings (/MD[d], /MT[d], /ML[d] (single-threaded until VS 2003)) + # plus set lib suffix for later use and project label accordingly + # see http://msdn.microsoft.com/en-us/library/aa278396(v=VS.60).aspx + # http://msdn.microsoft.com/en-us/library/2kzt1wy3(v=VS.71).aspx + set(LIB_RT_SUFFIX "md") # CMake defaults to /MD for MSVC + set(LIB_RT_OPTION "/MD") + # + if(NOT MSVC_SHARED_RT) # User wants to have static runtime libraries (/MT, /ML) + if(MSVC_STHREADED_RT) # User wants to have old single-threaded static runtime libraries + set(LIB_RT_SUFFIX "ml") + set(LIB_RT_OPTION "/ML") + if(NOT ${MSVC_VERSION} LESS 1400) + message(FATAL_ERROR "Single-threaded static runtime libraries (/ML) only available until VS .NET 2003 (7.1).") + endif() + else() + set(LIB_RT_SUFFIX "mt") + set(LIB_RT_OPTION "/MT") + endif() + + # correct linker options + foreach(flag_var CMAKE_C_FLAGS CMAKE_CXX_FLAGS) + foreach(config_name "" DEBUG RELEASE MINSIZEREL RELWITHDEBINFO) + set(var_name "${flag_var}") + if(NOT "${config_name}" STREQUAL "") + set(var_name "${var_name}_${config_name}") + endif() + string(REPLACE "/MD" "${LIB_RT_OPTION}" ${var_name} "${${var_name}}") + endforeach() + endforeach() + endif() + # + set(LABEL_SUFFIX "${LABEL_SUFFIX} ${LIB_RT_OPTION}") + + # b) Change prefix for static libraries + set(CMAKE_STATIC_LIBRARY_PREFIX "lib") # to distinguish static libraries from DLL import libs + + # c) Correct suffixes for static libraries + if(NOT BUILD_SHARED_LIBS) + ### General stuff + set(LIB_TARGET_SUFFIX "${LIB_SUFFIX}${LIB_RT_SUFFIX}") + endif() + + ### Project stuff + # /W3 = set warning level; see http://msdn.microsoft.com/en-us/library/thxezb7y.aspx + # /wd4127 = disable warning C4127 "conditional expression is constant"; see http://msdn.microsoft.com/en-us/library/6t66728h.aspx + # /wd4355 = disable warning C4355 "'this' : used in base member initializer list"; http://msdn.microsoft.com/en-us/library/3c594ae3.aspx + set(CMAKE_CXX_FLAGS "/W3 /wd4127 /wd4355 /D_SCL_SECURE_NO_WARNINGS ${CMAKE_CXX_FLAGS}") +endif() + + +### +### General install settings +### +if(WIN32) + set(_library_dir bin) # .dll are in PATH, like executables +else() + set(_library_dir lib) +endif() + +set(INCLUDE_INSTALL_DIR include/yaml-cpp) +set(LIB_INSTALL_DIR "${_library_dir}${LIB_SUFFIX}") + +set(_INSTALL_DESTINATIONS + RUNTIME DESTINATION bin + LIBRARY DESTINATION ${LIB_INSTALL_DIR} + ARCHIVE DESTINATION "lib${LIB_SUFFIX}" +) + + +### +### Library +### +add_library(yaml-cpp + ${sources} + ${public_headers} + ${private_headers} + ${contrib_sources} + ${contrib_public_headers} + ${contrib_private_headers} +) + +set_target_properties(yaml-cpp PROPERTIES + VERSION "${YAML_CPP_VERSION}" + SOVERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}" + PROJECT_LABEL "yaml-cpp ${LABEL_SUFFIX}" +) + +if(IPHONE) + set_target_properties(yaml-cpp PROPERTIES + XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "3.0" + ) +endif() + +if(MSVC) + if(NOT BUILD_SHARED_LIBS) + # correct library names + set_target_properties(yaml-cpp PROPERTIES + DEBUG_POSTFIX "${LIB_TARGET_SUFFIX}d" + RELEASE_POSTFIX "${LIB_TARGET_SUFFIX}" + MINSIZEREL_POSTFIX "${LIB_TARGET_SUFFIX}" + RELWITHDEBINFO_POSTFIX "${LIB_TARGET_SUFFIX}" + ) + endif() +endif() + +install(TARGETS yaml-cpp ${_INSTALL_DESTINATIONS}) +install( + FILES + ${public_headers} + ${contrib_public_headers} + DESTINATION ${INCLUDE_INSTALL_DIR} +) + +if(UNIX) + set(PC_FILE ${CMAKE_BINARY_DIR}/yaml-cpp.pc) + configure_file("yaml-cpp.pc.cmake" ${PC_FILE} @ONLY) + install(FILES ${PC_FILE} DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) +endif() + + +### +### Extras +### +if(YAML_CPP_BUILD_TOOLS) + add_subdirectory(test) + add_subdirectory(util) +endif() diff --git a/license.txt b/license.txt index 68a6f66..5bd9e1a 100644 --- a/license.txt +++ b/license.txt @@ -1,19 +1,19 @@ -Copyright (c) 2008 Jesse Beder. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +Copyright (c) 2008 Jesse Beder. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. From 95d05dcfa5409c653d4d9fd4acb344995299da24 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 21 Mar 2011 23:03:01 +0000 Subject: [PATCH 276/295] Switched project label to use 'nicer' suffix (e.g., md instead of /MD) --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 634d16e..20ec119 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -181,7 +181,7 @@ if(MSVC) endforeach() endif() # - set(LABEL_SUFFIX "${LABEL_SUFFIX} ${LIB_RT_OPTION}") + set(LABEL_SUFFIX "${LABEL_SUFFIX} ${LIB_RT_SUFFIX}") # b) Change prefix for static libraries set(CMAKE_STATIC_LIBRARY_PREFIX "lib") # to distinguish static libraries from DLL import libs From 2402c4d7e91916368c0a98aa8dd4fb9f6b1381ab Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 30 Mar 2011 01:33:02 +0000 Subject: [PATCH 277/295] Set version to 0.2.6 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 20ec119..9665ebd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ project(YAML_CPP) set(YAML_CPP_VERSION_MAJOR "0") set(YAML_CPP_VERSION_MINOR "2") -set(YAML_CPP_VERSION_PATCH "5") +set(YAML_CPP_VERSION_PATCH "6") set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}") enable_testing() From f7bee99fa3c6a1c3133810628b6ddc53e6117b22 Mon Sep 17 00:00:00 2001 From: jbeder Date: Tue, 3 May 2011 21:55:49 +0000 Subject: [PATCH 278/295] Added include for using 'NULL' (apparently gcc 4.6 is more strict) --- src/contrib/graphbuilderadapter.h | 1 + src/ptr_stack.h | 1 + src/ptr_vector.h | 1 + 3 files changed, 3 insertions(+) diff --git a/src/contrib/graphbuilderadapter.h b/src/contrib/graphbuilderadapter.h index 8e5cc07..4f0b80c 100644 --- a/src/contrib/graphbuilderadapter.h +++ b/src/contrib/graphbuilderadapter.h @@ -5,6 +5,7 @@ #pragma once #endif +#include #include #include #include "yaml-cpp/eventhandler.h" diff --git a/src/ptr_stack.h b/src/ptr_stack.h index 75fc923..4c6af11 100644 --- a/src/ptr_stack.h +++ b/src/ptr_stack.h @@ -6,6 +6,7 @@ #endif #include "yaml-cpp/noncopyable.h" +#include #include #include diff --git a/src/ptr_vector.h b/src/ptr_vector.h index e798208..aa103b8 100644 --- a/src/ptr_vector.h +++ b/src/ptr_vector.h @@ -6,6 +6,7 @@ #endif #include "yaml-cpp/noncopyable.h" +#include #include #include From ee446d00ea53f18750f505b1f0baaf0027d477a2 Mon Sep 17 00:00:00 2001 From: jbeder Date: Wed, 18 May 2011 21:07:25 +0000 Subject: [PATCH 279/295] Added emitting std::set (and refactored the stl emitters a bit) --- include/yaml-cpp/stlemitter.h | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/include/yaml-cpp/stlemitter.h b/include/yaml-cpp/stlemitter.h index 1b5d864..74dce1b 100644 --- a/include/yaml-cpp/stlemitter.h +++ b/include/yaml-cpp/stlemitter.h @@ -8,32 +8,37 @@ #include #include +#include #include namespace YAML { - template - inline Emitter& operator << (Emitter& emitter, const std::vector & v) { - typedef typename std::vector vec; + template + inline Emitter& EmitSeq(Emitter& emitter, const Seq& seq) { emitter << BeginSeq; - for(typename vec::const_iterator it=v.begin();it!=v.end();++it) - emitter << *it; - emitter << EndSeq; - return emitter; - } - - template - inline Emitter& operator << (Emitter& emitter, const std::list & v) { - typedef typename std::list list; - emitter << BeginSeq; - for(typename list::const_iterator it=v.begin();it!=v.end();++it) + for(typename Seq::const_iterator it=seq.begin();it!=seq.end();++it) emitter << *it; emitter << EndSeq; return emitter; } + template + inline Emitter& operator << (Emitter& emitter, const std::vector& v) { + return EmitSeq(emitter, v); + } + + template + inline Emitter& operator << (Emitter& emitter, const std::list& v) { + return EmitSeq(emitter, v); + } + + template + inline Emitter& operator << (Emitter& emitter, const std::set& v) { + return EmitSeq(emitter, v); + } + template - inline Emitter& operator << (Emitter& emitter, const std::map & m) { + inline Emitter& operator << (Emitter& emitter, const std::map& m) { typedef typename std::map map; emitter << BeginMap; for(typename map::const_iterator it=m.begin();it!=m.end();++it) From ede50424ef052068fc2a163e0cc8c60ebc0a2b35 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sun, 29 May 2011 02:17:49 +0000 Subject: [PATCH 280/295] Fixed includedir for the .pc.cmake file --- CMakeLists.txt | 4 +++- yaml-cpp.pc.cmake | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9665ebd..b34518d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -209,7 +209,9 @@ else() set(_library_dir lib) endif() -set(INCLUDE_INSTALL_DIR include/yaml-cpp) +set(INCLUDE_INSTALL_ROOT_DIR include) + +set(INCLUDE_INSTALL_DIR ${INCLUDE_INSTALL_ROOT_DIR}/yaml-cpp) set(LIB_INSTALL_DIR "${_library_dir}${LIB_SUFFIX}") set(_INSTALL_DESTINATIONS diff --git a/yaml-cpp.pc.cmake b/yaml-cpp.pc.cmake index cf4b3d0..04d343f 100644 --- a/yaml-cpp.pc.cmake +++ b/yaml-cpp.pc.cmake @@ -1,7 +1,7 @@ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@CMAKE_INSTALL_PREFIX@ libdir=${prefix}/@LIB_INSTALL_DIR@ -includedir=${prefix}/@INCLUDE_INSTALL_DIR@ +includedir=${prefix}/@INCLUDE_INSTALL_ROOT_DIR@ Name: Yaml-cpp Description: A YAML parser and emitter for C++ From 9ec2b96b19156ce5ac561b4401cfa60032dccd68 Mon Sep 17 00:00:00 2001 From: jbeder Date: Sun, 10 Jul 2011 16:27:40 +0000 Subject: [PATCH 281/295] Added parsing .inf and .nan (and friend) --- include/yaml-cpp/conversion.h | 27 ++++++++++++++- test/parsertests.cpp | 63 +++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/include/yaml-cpp/conversion.h b/include/yaml-cpp/conversion.h index 327f88d..6009fb7 100644 --- a/include/yaml-cpp/conversion.h +++ b/include/yaml-cpp/conversion.h @@ -8,6 +8,7 @@ #include "yaml-cpp/null.h" #include "yaml-cpp/traits.h" +#include #include #include @@ -21,12 +22,36 @@ namespace YAML YAML_CPP_API bool Convert(const std::string& input, bool& output); YAML_CPP_API bool Convert(const std::string& input, _Null& output); + inline bool IsInfinity(const std::string& input) { + return input == ".inf" || input == ".Inf" || input == ".INF" || + input == "+.inf" || input == "+.Inf" || input == "+.INF" || + input == "-.inf" || input == "-.Inf" || input == "-.INF"; + } + + inline bool IsNaN(const std::string& input) { + return input == ".nan" || input == ".NaN" || input == ".NAN"; + } + + template inline bool Convert(const std::string& input, T& output, typename enable_if >::type * = 0) { std::stringstream stream(input); stream.unsetf(std::ios::dec); stream >> output; - return !!stream; + if(!!stream) + return true; + + if(std::numeric_limits::has_infinity && IsInfinity(input)) { + output = std::numeric_limits::infinity(); + return true; + } + + if(std::numeric_limits::has_quiet_NaN && IsNaN(input)) { + output = std::numeric_limits::quiet_NaN(); + return true; + } + + return false; } } diff --git a/test/parsertests.cpp b/test/parsertests.cpp index 7b4174e..c5e52b9 100644 --- a/test/parsertests.cpp +++ b/test/parsertests.cpp @@ -803,6 +803,67 @@ namespace Test return ExpectedTagValue(node, "!"); } + + bool Infinity() + { + std::string input = + "- .inf\n" + "- .Inf\n" + "- .INF\n" + "- +.inf\n" + "- +.Inf\n" + "- +.INF\n" + "- -.inf\n" + "- -.Inf\n" + "- -.INF\n"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + for(unsigned i=0;i() != std::numeric_limits::infinity()) + return false; + for(unsigned i=0;i() != std::numeric_limits::infinity()) + return false; + for(unsigned i=0;i() != std::numeric_limits::infinity()) + return false; + return true; + } + + bool NaN() + { + std::string input = + "- .nan\n" + "- .NaN\n" + "- .NAN\n"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + for(unsigned i=0;i> d; + if(d == d) + return false; + } + for(unsigned i=0;i> d; + if(d == d) + return false; + } + for(unsigned i=0;i> d; + if(d == d) + return false; + } + return true; + } } namespace { @@ -1079,6 +1140,8 @@ namespace Test RunParserTest(&Parser::DefaultPlainScalarTag, "default plain scalar tag", passed, total); RunParserTest(&Parser::DefaultSequenceTag, "default sequence tag", passed, total); RunParserTest(&Parser::ExplicitNonSpecificSequenceTag, "explicit, non-specific sequence tag", passed, total); + RunParserTest(&Parser::Infinity, "infinity", passed, total); + RunParserTest(&Parser::NaN, "NaN", passed, total); RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed, total); RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed, total); From 7f9aa35edb56cb752e6fd84dbb68d4c5dc0d370d Mon Sep 17 00:00:00 2001 From: jbeder Date: Sun, 10 Jul 2011 18:29:44 +0000 Subject: [PATCH 282/295] Fixed negative infinity parsing --- include/yaml-cpp/conversion.h | 19 +++++++++++++------ test/parsertests.cpp | 6 +++--- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/include/yaml-cpp/conversion.h b/include/yaml-cpp/conversion.h index 6009fb7..adf72d8 100644 --- a/include/yaml-cpp/conversion.h +++ b/include/yaml-cpp/conversion.h @@ -23,9 +23,11 @@ namespace YAML YAML_CPP_API bool Convert(const std::string& input, _Null& output); inline bool IsInfinity(const std::string& input) { - return input == ".inf" || input == ".Inf" || input == ".INF" || - input == "+.inf" || input == "+.Inf" || input == "+.INF" || - input == "-.inf" || input == "-.Inf" || input == "-.INF"; + return input == ".inf" || input == ".Inf" || input == ".INF" || input == "+.inf" || input == "+.Inf" || input == "+.INF"; + } + + inline bool IsNegativeInfinity(const std::string& input) { + return input == "-.inf" || input == "-.Inf" || input == "-.INF"; } inline bool IsNaN(const std::string& input) { @@ -41,9 +43,14 @@ namespace YAML if(!!stream) return true; - if(std::numeric_limits::has_infinity && IsInfinity(input)) { - output = std::numeric_limits::infinity(); - return true; + if(std::numeric_limits::has_infinity) { + if(IsInfinity(input)) { + output = std::numeric_limits::infinity(); + return true; + } else if(IsNegativeInfinity(input)) { + output = -std::numeric_limits::infinity(); + return true; + } } if(std::numeric_limits::has_quiet_NaN && IsNaN(input)) { diff --git a/test/parsertests.cpp b/test/parsertests.cpp index c5e52b9..e7da3b7 100644 --- a/test/parsertests.cpp +++ b/test/parsertests.cpp @@ -822,13 +822,13 @@ namespace Test parser.GetNextDocument(doc); for(unsigned i=0;i() != std::numeric_limits::infinity()) + if(doc[i].to() != (i < 6 ? +1 : -1) * std::numeric_limits::infinity()) return false; for(unsigned i=0;i() != std::numeric_limits::infinity()) + if(doc[i].to() != (i < 6 ? +1 : -1) * std::numeric_limits::infinity()) return false; for(unsigned i=0;i() != std::numeric_limits::infinity()) + if(doc[i].to() != (i < 6 ? +1 : -1) * std::numeric_limits::infinity()) return false; return true; } From dae85e28e21390d3cc3a65e1e061f1b7600049b4 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 4 Aug 2011 18:47:37 +0000 Subject: [PATCH 283/295] Included for NULL --- src/ptr_stack.h | 1 + src/ptr_vector.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/ptr_stack.h b/src/ptr_stack.h index 4c6af11..03dd364 100644 --- a/src/ptr_stack.h +++ b/src/ptr_stack.h @@ -6,6 +6,7 @@ #endif #include "yaml-cpp/noncopyable.h" +#include #include #include #include diff --git a/src/ptr_vector.h b/src/ptr_vector.h index aa103b8..d1742a3 100644 --- a/src/ptr_vector.h +++ b/src/ptr_vector.h @@ -6,6 +6,7 @@ #endif #include "yaml-cpp/noncopyable.h" +#include #include #include #include From a1fc9d8d8869ac5874276d88132e3361a4be42a0 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 4 Aug 2011 21:47:57 +0000 Subject: [PATCH 284/295] Forced a newline after any comments --- src/emitter.cpp | 12 ++++++++++-- src/emitterutils.cpp | 2 +- test/emittertests.cpp | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/emitter.cpp b/src/emitter.cpp index ad21e22..c49fcc9 100644 --- a/src/emitter.cpp +++ b/src/emitter.cpp @@ -186,6 +186,7 @@ namespace YAML case ES_WRITING_FLOW_SEQ_ENTRY: return true; case ES_DONE_WITH_FLOW_SEQ_ENTRY: + EmitSeparationIfNecessary(); m_stream << ','; m_pState->RequireSoftSeparation(); m_pState->SwitchState(ES_WAITING_FOR_FLOW_SEQ_ENTRY); @@ -221,9 +222,9 @@ namespace YAML m_pState->SetError(ErrorMsg::EXPECTED_KEY_TOKEN); return true; case ES_WAITING_FOR_FLOW_MAP_KEY: + EmitSeparationIfNecessary(); m_pState->SwitchState(ES_WRITING_FLOW_MAP_KEY); if(m_pState->CurrentlyInLongKey()) { - EmitSeparationIfNecessary(); m_stream << '?'; m_pState->RequireSoftSeparation(); } @@ -234,6 +235,7 @@ namespace YAML m_pState->SetError(ErrorMsg::EXPECTED_VALUE_TOKEN); return true; case ES_WAITING_FOR_FLOW_MAP_VALUE: + EmitSeparationIfNecessary(); m_stream << ':'; m_pState->RequireSoftSeparation(); m_pState->SwitchState(ES_WRITING_FLOW_MAP_VALUE); @@ -496,6 +498,7 @@ namespace YAML } else if(flowType == FT_FLOW) { // Note: flow maps are allowed to be empty assert(curState == ES_DONE_WITH_FLOW_MAP_VALUE || curState == ES_WAITING_FOR_FLOW_MAP_ENTRY); + EmitSeparationIfNecessary(); m_stream << "}"; } else assert(false); @@ -526,6 +529,7 @@ namespace YAML m_pState->UnsetSeparation(); m_pState->SwitchState(ES_WAITING_FOR_BLOCK_MAP_KEY); } else if(flowType == FT_FLOW) { + EmitSeparationIfNecessary(); if(curState == ES_DONE_WITH_FLOW_MAP_VALUE) { m_stream << ','; m_pState->RequireSoftSeparation(); @@ -796,8 +800,12 @@ namespace YAML if(!good()) return *this; - m_stream << Indentation(m_pState->GetPreCommentIndent()); + if(m_stream.col() > 0) + m_stream << Indentation(m_pState->GetPreCommentIndent()); Utils::WriteComment(m_stream, comment.content, m_pState->GetPostCommentIndent()); + m_pState->RequireHardSeparation(); + m_pState->ForceHardSeparation(); + return *this; } diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index 38bd18f..5bc0ba9 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -267,7 +267,7 @@ namespace YAML bool WriteComment(ostream& out, const std::string& str, int postCommentIndent) { - unsigned curIndent = out.col(); + const unsigned curIndent = out.col(); out << "#" << Indentation(postCommentIndent); int codePoint; for(std::string::const_iterator i = str.begin(); diff --git a/test/emittertests.cpp b/test/emittertests.cpp index c3e0be7..246cd2d 100644 --- a/test/emittertests.cpp +++ b/test/emittertests.cpp @@ -503,6 +503,40 @@ namespace Test desiredOutput = "? long key # long key\n: value"; } + + void InitialComment(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Comment("A comment describing the purpose of the file."); + out << YAML::BeginMap << YAML::Key << "key" << YAML::Value << "value" << YAML::EndMap; + + desiredOutput = "# A comment describing the purpose of the file.\nkey: value"; + } + + void InitialCommentWithDocIndicator(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginDoc << YAML::Comment("A comment describing the purpose of the file."); + out << YAML::BeginMap << YAML::Key << "key" << YAML::Value << "value" << YAML::EndMap; + + desiredOutput = "---\n# A comment describing the purpose of the file.\nkey: value"; + } + + void CommentInFlowSeq(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Flow << YAML::BeginSeq << "foo" << YAML::Comment("foo!") << "bar" << YAML::EndSeq; + + desiredOutput = "[foo # foo!\n, bar]"; + } + + void CommentInFlowMap(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Flow << YAML::BeginMap; + out << YAML::Key << "foo" << YAML::Comment("foo!") << YAML::Value << "foo value"; + out << YAML::Key << "bar" << YAML::Value << "bar value" << YAML::Comment("bar!"); + out << YAML::Key << "baz" << YAML::Comment("baz!") << YAML::Value << "baz value" << YAML::Comment("baz!"); + out << YAML::EndMap; + + desiredOutput = "{foo # foo!\n: foo value, bar: bar value # bar!\n, baz # baz!\n: baz value # baz!\n}"; + } void Indentation(YAML::Emitter& out, std::string& desiredOutput) { @@ -980,6 +1014,10 @@ namespace Test RunEmitterTest(&Emitter::SimpleComment, "simple comment", passed, total); RunEmitterTest(&Emitter::MultiLineComment, "multi-line comment", passed, total); RunEmitterTest(&Emitter::ComplexComments, "complex comments", passed, total); + RunEmitterTest(&Emitter::InitialComment, "initial comment", passed, total); + RunEmitterTest(&Emitter::InitialCommentWithDocIndicator, "initial comment with doc indicator", passed, total); + RunEmitterTest(&Emitter::CommentInFlowSeq, "comment in flow seq", passed, total); + RunEmitterTest(&Emitter::CommentInFlowMap, "comment in flow map", passed, total); RunEmitterTest(&Emitter::Indentation, "indentation", passed, total); RunEmitterTest(&Emitter::SimpleGlobalSettings, "simple global settings", passed, total); RunEmitterTest(&Emitter::ComplexGlobalSettings, "complex global settings", passed, total); From 088401fa88773510d46077b6398cd9fa72644360 Mon Sep 17 00:00:00 2001 From: jbeder Date: Thu, 4 Aug 2011 21:50:04 +0000 Subject: [PATCH 285/295] Added test for anchor/alias in flow --- test/emittertests.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/emittertests.cpp b/test/emittertests.cpp index 246cd2d..329ed3b 100644 --- a/test/emittertests.cpp +++ b/test/emittertests.cpp @@ -282,6 +282,20 @@ namespace Test desiredOutput = "- &fred ~\n- *fred"; } + void AliasAndAnchorInFlow(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::Flow << YAML::BeginSeq; + out << YAML::Anchor("fred"); + out << YAML::BeginMap; + out << YAML::Key << "name" << YAML::Value << "Fred"; + out << YAML::Key << "age" << YAML::Value << 42; + out << YAML::EndMap; + out << YAML::Alias("fred"); + out << YAML::EndSeq; + + desiredOutput = "[&fred {name: Fred, age: 42}, *fred]"; + } + void SimpleVerbatimTag(YAML::Emitter& out, std::string& desiredOutput) { out << YAML::VerbatimTag("!foo") << "bar"; @@ -997,6 +1011,7 @@ namespace Test RunEmitterTest(&Emitter::BlockMapAsKey, "block map as key", passed, total); RunEmitterTest(&Emitter::AliasAndAnchor, "alias and anchor", passed, total); RunEmitterTest(&Emitter::AliasAndAnchorWithNull, "alias and anchor with null", passed, total); + RunEmitterTest(&Emitter::AliasAndAnchorInFlow, "alias and anchor in flow", passed, total); RunEmitterTest(&Emitter::SimpleVerbatimTag, "simple verbatim tag", passed, total); RunEmitterTest(&Emitter::VerbatimTagInBlockSeq, "verbatim tag in block seq", passed, total); RunEmitterTest(&Emitter::VerbatimTagInFlowSeq, "verbatim tag in flow seq", passed, total); From b5eaeac0b0cb03e57a941cb0e676186511c00492 Mon Sep 17 00:00:00 2001 From: jbeder Date: Mon, 22 Aug 2011 21:37:51 +0000 Subject: [PATCH 286/295] Removed ATOMIC_TYPE, an old enum that wasn't used any more --- include/yaml-cpp/emitter.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/yaml-cpp/emitter.h b/include/yaml-cpp/emitter.h index 86d3ed8..4cedb0e 100644 --- a/include/yaml-cpp/emitter.h +++ b/include/yaml-cpp/emitter.h @@ -71,8 +71,6 @@ namespace YAML void PostWriteStreamable(const std::stringstream& str); private: - enum ATOMIC_TYPE { AT_SCALAR, AT_SEQ, AT_BLOCK_SEQ, AT_FLOW_SEQ, AT_MAP, AT_BLOCK_MAP, AT_FLOW_MAP }; - void PreAtomicWrite(); bool GotoNextPreAtomicState(); void PostAtomicWrite(); From 44bee0b8ad4791c56f1c3a74e41c56e64adf0db7 Mon Sep 17 00:00:00 2001 From: beder Date: Wed, 24 Aug 2011 02:59:58 -0500 Subject: [PATCH 288/295] Added .hgeol for native eols --- .hgeol | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .hgeol diff --git a/.hgeol b/.hgeol new file mode 100644 index 0000000..6b36803 --- /dev/null +++ b/.hgeol @@ -0,0 +1,4 @@ +**.h = native +**.c = native +**.cpp = native +**.txt = native From ced351dec8e9ac9f190842db0f1606d752f3f17e Mon Sep 17 00:00:00 2001 From: beder Date: Tue, 6 Sep 2011 00:16:03 -0500 Subject: [PATCH 289/295] Switched the 'pragma once' to only happen on MSVC, or gcc >= 3.4 (it was causing trouble on the sun compiler) --- include/yaml-cpp/aliasmanager.h | 2 +- include/yaml-cpp/anchor.h | 2 +- include/yaml-cpp/contrib/anchordict.h | 2 +- include/yaml-cpp/contrib/graphbuilder.h | 2 +- include/yaml-cpp/conversion.h | 2 +- include/yaml-cpp/dll.h | 2 +- include/yaml-cpp/emitfromevents.h | 2 +- include/yaml-cpp/emitter.h | 2 +- include/yaml-cpp/emittermanip.h | 2 +- include/yaml-cpp/eventhandler.h | 2 +- include/yaml-cpp/exceptions.h | 2 +- include/yaml-cpp/iterator.h | 2 +- include/yaml-cpp/ltnode.h | 2 +- include/yaml-cpp/mark.h | 2 +- include/yaml-cpp/node.h | 2 +- include/yaml-cpp/nodeimpl.h | 2 +- include/yaml-cpp/nodereadimpl.h | 2 +- include/yaml-cpp/nodeutil.h | 2 +- include/yaml-cpp/noncopyable.h | 2 +- include/yaml-cpp/null.h | 2 +- include/yaml-cpp/ostream.h | 2 +- include/yaml-cpp/parser.h | 2 +- include/yaml-cpp/stlemitter.h | 2 +- include/yaml-cpp/stlnode.h | 2 +- include/yaml-cpp/traits.h | 2 +- include/yaml-cpp/yaml.h | 2 +- src/collectionstack.h | 2 +- src/contrib/graphbuilderadapter.h | 2 +- src/directives.h | 2 +- src/emitterstate.h | 2 +- src/emitterutils.h | 2 +- src/exp.h | 2 +- src/indentation.h | 2 +- src/iterpriv.h | 2 +- src/nodebuilder.h | 2 +- src/nodeownership.h | 2 +- src/ptr_stack.h | 2 +- src/ptr_vector.h | 2 +- src/regex.h | 2 +- src/regeximpl.h | 2 +- src/scanner.h | 2 +- src/scanscalar.h | 2 +- src/scantag.h | 2 +- src/setting.h | 2 +- src/singledocparser.h | 2 +- src/stream.h | 2 +- src/streamcharsource.h | 2 +- src/stringsource.h | 2 +- src/tag.h | 2 +- src/token.h | 2 +- test/emittertests.h | 2 +- test/parsertests.h | 2 +- test/spectests.h | 2 +- test/tests.h | 2 +- 54 files changed, 54 insertions(+), 54 deletions(-) diff --git a/include/yaml-cpp/aliasmanager.h b/include/yaml-cpp/aliasmanager.h index d650269..e90c93d 100644 --- a/include/yaml-cpp/aliasmanager.h +++ b/include/yaml-cpp/aliasmanager.h @@ -1,7 +1,7 @@ #ifndef ALIASMANAGER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define ALIASMANAGER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/anchor.h b/include/yaml-cpp/anchor.h index 175d4d7..433f2fa 100644 --- a/include/yaml-cpp/anchor.h +++ b/include/yaml-cpp/anchor.h @@ -1,7 +1,7 @@ #ifndef ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/contrib/anchordict.h b/include/yaml-cpp/contrib/anchordict.h index 8638aab..e483dc4 100644 --- a/include/yaml-cpp/contrib/anchordict.h +++ b/include/yaml-cpp/contrib/anchordict.h @@ -1,7 +1,7 @@ #ifndef ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/contrib/graphbuilder.h b/include/yaml-cpp/contrib/graphbuilder.h index 7c09fb2..6739a12 100644 --- a/include/yaml-cpp/contrib/graphbuilder.h +++ b/include/yaml-cpp/contrib/graphbuilder.h @@ -1,7 +1,7 @@ #ifndef GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/conversion.h b/include/yaml-cpp/conversion.h index adf72d8..ba7eed1 100644 --- a/include/yaml-cpp/conversion.h +++ b/include/yaml-cpp/conversion.h @@ -1,7 +1,7 @@ #ifndef CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/dll.h b/include/yaml-cpp/dll.h index c09cf6b..ea13840 100644 --- a/include/yaml-cpp/dll.h +++ b/include/yaml-cpp/dll.h @@ -1,7 +1,7 @@ #ifndef DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/emitfromevents.h b/include/yaml-cpp/emitfromevents.h index 4f9badc..e11ae64 100644 --- a/include/yaml-cpp/emitfromevents.h +++ b/include/yaml-cpp/emitfromevents.h @@ -1,7 +1,7 @@ #ifndef EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/emitter.h b/include/yaml-cpp/emitter.h index 4cedb0e..eebdd4c 100644 --- a/include/yaml-cpp/emitter.h +++ b/include/yaml-cpp/emitter.h @@ -1,7 +1,7 @@ #ifndef EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/emittermanip.h b/include/yaml-cpp/emittermanip.h index 1dc5766..a096d10 100644 --- a/include/yaml-cpp/emittermanip.h +++ b/include/yaml-cpp/emittermanip.h @@ -1,7 +1,7 @@ #ifndef EMITTERMANIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EMITTERMANIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/eventhandler.h b/include/yaml-cpp/eventhandler.h index 80afdb4..3173a1f 100644 --- a/include/yaml-cpp/eventhandler.h +++ b/include/yaml-cpp/eventhandler.h @@ -1,7 +1,7 @@ #ifndef EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/exceptions.h b/include/yaml-cpp/exceptions.h index e940499..394d586 100644 --- a/include/yaml-cpp/exceptions.h +++ b/include/yaml-cpp/exceptions.h @@ -1,7 +1,7 @@ #ifndef EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/iterator.h b/include/yaml-cpp/iterator.h index 2397db9..400ee34 100644 --- a/include/yaml-cpp/iterator.h +++ b/include/yaml-cpp/iterator.h @@ -1,7 +1,7 @@ #ifndef ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/ltnode.h b/include/yaml-cpp/ltnode.h index cf85435..30b4f95 100644 --- a/include/yaml-cpp/ltnode.h +++ b/include/yaml-cpp/ltnode.h @@ -1,7 +1,7 @@ #ifndef LTNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define LTNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/mark.h b/include/yaml-cpp/mark.h index 09057da..7c80fbc 100644 --- a/include/yaml-cpp/mark.h +++ b/include/yaml-cpp/mark.h @@ -1,7 +1,7 @@ #ifndef MARK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define MARK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/node.h b/include/yaml-cpp/node.h index ff752c4..8e16636 100644 --- a/include/yaml-cpp/node.h +++ b/include/yaml-cpp/node.h @@ -1,7 +1,7 @@ #ifndef NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/nodeimpl.h b/include/yaml-cpp/nodeimpl.h index d26968a..4906a98 100644 --- a/include/yaml-cpp/nodeimpl.h +++ b/include/yaml-cpp/nodeimpl.h @@ -1,7 +1,7 @@ #ifndef NODEIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define NODEIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/nodereadimpl.h b/include/yaml-cpp/nodereadimpl.h index 9ad5b83..6838dc5 100644 --- a/include/yaml-cpp/nodereadimpl.h +++ b/include/yaml-cpp/nodereadimpl.h @@ -1,7 +1,7 @@ #ifndef NODEREADIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define NODEREADIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/nodeutil.h b/include/yaml-cpp/nodeutil.h index 98ea4fa..d0c01d2 100644 --- a/include/yaml-cpp/nodeutil.h +++ b/include/yaml-cpp/nodeutil.h @@ -1,7 +1,7 @@ #ifndef NODEUTIL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define NODEUTIL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/noncopyable.h b/include/yaml-cpp/noncopyable.h index 1614b68..8e61e43 100644 --- a/include/yaml-cpp/noncopyable.h +++ b/include/yaml-cpp/noncopyable.h @@ -1,7 +1,7 @@ #ifndef NONCOPYABLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define NONCOPYABLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/null.h b/include/yaml-cpp/null.h index 9c7986b..c3450ee 100644 --- a/include/yaml-cpp/null.h +++ b/include/yaml-cpp/null.h @@ -1,7 +1,7 @@ #ifndef NULL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define NULL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/ostream.h b/include/yaml-cpp/ostream.h index 90258ba..65839b1 100644 --- a/include/yaml-cpp/ostream.h +++ b/include/yaml-cpp/ostream.h @@ -1,7 +1,7 @@ #ifndef OSTREAM_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define OSTREAM_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/parser.h b/include/yaml-cpp/parser.h index 32a2d16..3463cc3 100644 --- a/include/yaml-cpp/parser.h +++ b/include/yaml-cpp/parser.h @@ -1,7 +1,7 @@ #ifndef PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/stlemitter.h b/include/yaml-cpp/stlemitter.h index 74dce1b..f8ff20e 100644 --- a/include/yaml-cpp/stlemitter.h +++ b/include/yaml-cpp/stlemitter.h @@ -1,7 +1,7 @@ #ifndef STLEMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define STLEMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/stlnode.h b/include/yaml-cpp/stlnode.h index 8d50f7f..40d4ae7 100644 --- a/include/yaml-cpp/stlnode.h +++ b/include/yaml-cpp/stlnode.h @@ -1,7 +1,7 @@ #ifndef STLNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define STLNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/traits.h b/include/yaml-cpp/traits.h index 32a3155..09eead4 100644 --- a/include/yaml-cpp/traits.h +++ b/include/yaml-cpp/traits.h @@ -1,7 +1,7 @@ #ifndef TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/include/yaml-cpp/yaml.h b/include/yaml-cpp/yaml.h index 674430e..d2ca43b 100644 --- a/include/yaml-cpp/yaml.h +++ b/include/yaml-cpp/yaml.h @@ -1,7 +1,7 @@ #ifndef YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/collectionstack.h b/src/collectionstack.h index 5274546..4a986bc 100644 --- a/src/collectionstack.h +++ b/src/collectionstack.h @@ -1,7 +1,7 @@ #ifndef COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/contrib/graphbuilderadapter.h b/src/contrib/graphbuilderadapter.h index 4f0b80c..3ef8ab6 100644 --- a/src/contrib/graphbuilderadapter.h +++ b/src/contrib/graphbuilderadapter.h @@ -1,7 +1,7 @@ #ifndef GRAPHBUILDERADAPTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define GRAPHBUILDERADAPTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/directives.h b/src/directives.h index 2fa6f62..a3308f7 100644 --- a/src/directives.h +++ b/src/directives.h @@ -1,7 +1,7 @@ #ifndef DIRECTIVES_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define DIRECTIVES_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/emitterstate.h b/src/emitterstate.h index 9c8136e..90be656 100644 --- a/src/emitterstate.h +++ b/src/emitterstate.h @@ -1,7 +1,7 @@ #ifndef EMITTERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EMITTERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/emitterutils.h b/src/emitterutils.h index 5b3de82..b6c0b70 100644 --- a/src/emitterutils.h +++ b/src/emitterutils.h @@ -1,7 +1,7 @@ #ifndef EMITTERUTILS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EMITTERUTILS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/exp.h b/src/exp.h index 0200d25..703641a 100644 --- a/src/exp.h +++ b/src/exp.h @@ -1,7 +1,7 @@ #ifndef EXP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EXP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/indentation.h b/src/indentation.h index 89d68df..25f684f 100644 --- a/src/indentation.h +++ b/src/indentation.h @@ -1,7 +1,7 @@ #ifndef INDENTATION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define INDENTATION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/iterpriv.h b/src/iterpriv.h index 8e2ab22..c511e8a 100644 --- a/src/iterpriv.h +++ b/src/iterpriv.h @@ -1,7 +1,7 @@ #ifndef ITERPRIV_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define ITERPRIV_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/nodebuilder.h b/src/nodebuilder.h index eba403a..9c1d16a 100644 --- a/src/nodebuilder.h +++ b/src/nodebuilder.h @@ -1,7 +1,7 @@ #ifndef NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/nodeownership.h b/src/nodeownership.h index aae9b99..6987081 100644 --- a/src/nodeownership.h +++ b/src/nodeownership.h @@ -1,7 +1,7 @@ #ifndef NODE_OWNERSHIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define NODE_OWNERSHIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/ptr_stack.h b/src/ptr_stack.h index 03dd364..bf454fb 100644 --- a/src/ptr_stack.h +++ b/src/ptr_stack.h @@ -1,7 +1,7 @@ #ifndef PTR_STACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define PTR_STACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/ptr_vector.h b/src/ptr_vector.h index d1742a3..7b936cb 100644 --- a/src/ptr_vector.h +++ b/src/ptr_vector.h @@ -1,7 +1,7 @@ #ifndef PTR_VECTOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define PTR_VECTOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/regex.h b/src/regex.h index d797e9a..8722e62 100644 --- a/src/regex.h +++ b/src/regex.h @@ -1,7 +1,7 @@ #ifndef REGEX_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define REGEX_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/regeximpl.h b/src/regeximpl.h index aad9708..d5c20d7 100644 --- a/src/regeximpl.h +++ b/src/regeximpl.h @@ -1,7 +1,7 @@ #ifndef REGEXIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define REGEXIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/scanner.h b/src/scanner.h index 59857ed..bc8dcbe 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -1,7 +1,7 @@ #ifndef SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/scanscalar.h b/src/scanscalar.h index 52123e7..c198cb1 100644 --- a/src/scanscalar.h +++ b/src/scanscalar.h @@ -1,7 +1,7 @@ #ifndef SCANSCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define SCANSCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/scantag.h b/src/scantag.h index 869d9e8..38437c0 100644 --- a/src/scantag.h +++ b/src/scantag.h @@ -1,7 +1,7 @@ #ifndef SCANTAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define SCANTAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/setting.h b/src/setting.h index f503ad2..806ccda 100644 --- a/src/setting.h +++ b/src/setting.h @@ -1,7 +1,7 @@ #ifndef SETTING_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define SETTING_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/singledocparser.h b/src/singledocparser.h index 86688a6..3798dcc 100644 --- a/src/singledocparser.h +++ b/src/singledocparser.h @@ -1,7 +1,7 @@ #ifndef SINGLEDOCPARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define SINGLEDOCPARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/stream.h b/src/stream.h index e2fd4b5..90a401e 100644 --- a/src/stream.h +++ b/src/stream.h @@ -1,7 +1,7 @@ #ifndef STREAM_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define STREAM_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/streamcharsource.h b/src/streamcharsource.h index 55e9294..21fae4e 100644 --- a/src/streamcharsource.h +++ b/src/streamcharsource.h @@ -1,7 +1,7 @@ #ifndef STREAMCHARSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define STREAMCHARSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/stringsource.h b/src/stringsource.h index 8a45755..21be3c9 100644 --- a/src/stringsource.h +++ b/src/stringsource.h @@ -1,7 +1,7 @@ #ifndef STRINGSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define STRINGSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/tag.h b/src/tag.h index 675b15e..5f77548 100644 --- a/src/tag.h +++ b/src/tag.h @@ -1,7 +1,7 @@ #ifndef TAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define TAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/src/token.h b/src/token.h index 11e97a3..9807e25 100644 --- a/src/token.h +++ b/src/token.h @@ -1,7 +1,7 @@ #ifndef TOKEN_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define TOKEN_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/test/emittertests.h b/test/emittertests.h index 4ba5f72..e7c6ac5 100644 --- a/test/emittertests.h +++ b/test/emittertests.h @@ -1,7 +1,7 @@ #ifndef EMITTERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define EMITTERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/test/parsertests.h b/test/parsertests.h index a67fff8..f3de1b8 100644 --- a/test/parsertests.h +++ b/test/parsertests.h @@ -1,7 +1,7 @@ #ifndef PARSERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define PARSERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/test/spectests.h b/test/spectests.h index e8acfb7..8561d08 100644 --- a/test/spectests.h +++ b/test/spectests.h @@ -1,7 +1,7 @@ #ifndef SPECTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define SPECTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif diff --git a/test/tests.h b/test/tests.h index ec466a4..757dbc5 100644 --- a/test/tests.h +++ b/test/tests.h @@ -1,7 +1,7 @@ #ifndef TESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define TESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 -#if !defined(__GNUC__) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4) // GCC supports "pragma once" correctly since 3.4 +#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 #pragma once #endif From ec3a9ecbf044b0d906ee6f58b6b2c92e80bc0586 Mon Sep 17 00:00:00 2001 From: beder Date: Tue, 6 Sep 2011 00:24:10 -0500 Subject: [PATCH 290/295] Fixed empty string emitter bug (it now with auto-quote it --- src/emitterutils.cpp | 3 +++ test/emittertests.cpp | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index 5bc0ba9..be512af 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -128,6 +128,9 @@ namespace YAML } bool IsValidPlainScalar(const std::string& str, bool inFlow, bool allowOnlyAscii) { + if(str.empty()) + return false; + // first check the start const RegEx& start = (inFlow ? Exp::PlainScalarInFlow() : Exp::PlainScalar()); if(!start.Matches(str)) diff --git a/test/emittertests.cpp b/test/emittertests.cpp index 329ed3b..a7c13d8 100644 --- a/test/emittertests.cpp +++ b/test/emittertests.cpp @@ -846,6 +846,14 @@ namespace Test out << "Oops"; desiredOutput = "Hi\n---\nBye\n---\nOops"; } + + void EmptyString(YAML::Emitter& out, std::string& desiredOutput) + { + out << YAML::BeginMap; + out << YAML::Key << "key" << YAML::Value << ""; + out << YAML::EndMap; + desiredOutput = "key: \"\""; + } //////////////////////////////////////////////////////////////////////////////////////////////////////// // incorrect emitting @@ -1058,6 +1066,7 @@ namespace Test RunEmitterTest(&Emitter::BoolFormatting, "bool formatting", passed, total); RunEmitterTest(&Emitter::DocStartAndEnd, "doc start and end", passed, total); RunEmitterTest(&Emitter::ImplicitDocStart, "implicit doc start", passed, total); + RunEmitterTest(&Emitter::EmptyString, "empty string", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total); From a8fdb1718da0458a5ea924b7ebf4da17facf35ab Mon Sep 17 00:00:00 2001 From: beder Date: Tue, 6 Sep 2011 00:32:53 -0500 Subject: [PATCH 291/295] Added overload for operator [] for char * (non-const version) --- include/yaml-cpp/node.h | 2 ++ include/yaml-cpp/nodeimpl.h | 8 ++++++++ test/parsertests.cpp | 17 +++++++++++++++++ 3 files changed, 27 insertions(+) diff --git a/include/yaml-cpp/node.h b/include/yaml-cpp/node.h index 8e16636..2c0a686 100644 --- a/include/yaml-cpp/node.h +++ b/include/yaml-cpp/node.h @@ -77,7 +77,9 @@ namespace YAML // specific to maps const Node *FindValue(const char *key) const; + const Node *FindValue(char *key) const; const Node& operator [] (const char *key) const; + const Node& operator [] (char *key) const; // for tags const std::string& Tag() const { return m_tag; } diff --git a/include/yaml-cpp/nodeimpl.h b/include/yaml-cpp/nodeimpl.h index 4906a98..6ea24e4 100644 --- a/include/yaml-cpp/nodeimpl.h +++ b/include/yaml-cpp/nodeimpl.h @@ -68,10 +68,18 @@ namespace YAML inline const Node *Node::FindValue(const char *key) const { return FindValue(std::string(key)); } + + inline const Node *Node::FindValue(char *key) const { + return FindValue(std::string(key)); + } inline const Node& Node::operator [] (const char *key) const { return GetValue(std::string(key)); } + + inline const Node& Node::operator [] (char *key) const { + return GetValue(std::string(key)); + } } #endif // NODEIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/test/parsertests.cpp b/test/parsertests.cpp index e7da3b7..f6218db 100644 --- a/test/parsertests.cpp +++ b/test/parsertests.cpp @@ -864,6 +864,22 @@ namespace Test } return true; } + + bool NonConstKey() + { + std::string input = "{a: 1}"; + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + std::vector key(2); + key[0] = 'a'; + key[1] = '\0'; + if(doc[&key[0]].to() != 1) + return false; + return true; + } } namespace { @@ -1142,6 +1158,7 @@ namespace Test RunParserTest(&Parser::ExplicitNonSpecificSequenceTag, "explicit, non-specific sequence tag", passed, total); RunParserTest(&Parser::Infinity, "infinity", passed, total); RunParserTest(&Parser::NaN, "NaN", passed, total); + RunParserTest(&Parser::NonConstKey, "non const key", passed, total); RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed, total); RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed, total); From 126dfdb155a5c9ffa819a631d33b153e67ee8932 Mon Sep 17 00:00:00 2001 From: beder Date: Tue, 6 Sep 2011 00:39:31 -0500 Subject: [PATCH 292/295] Switched YAML::Binary interface to use unsigned chars, not chars --- include/yaml-cpp/emittermanip.h | 6 +++--- src/emitterutils.cpp | 2 +- src/emitterutils.h | 2 +- test/emittertests.cpp | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/yaml-cpp/emittermanip.h b/include/yaml-cpp/emittermanip.h index a096d10..5c63419 100644 --- a/include/yaml-cpp/emittermanip.h +++ b/include/yaml-cpp/emittermanip.h @@ -127,12 +127,12 @@ namespace YAML } struct _Binary { - _Binary(const char *data_, std::size_t size_): data(data_), size(size_) {} - const char *data; + _Binary(const unsigned char *data_, std::size_t size_): data(data_), size(size_) {} + const unsigned char *data; std::size_t size; }; - inline _Binary Binary(const char *data, std::size_t size) { + inline _Binary Binary(const unsigned char *data, std::size_t size) { return _Binary(data, size); } } diff --git a/src/emitterutils.cpp b/src/emitterutils.cpp index be512af..95a01fa 100644 --- a/src/emitterutils.cpp +++ b/src/emitterutils.cpp @@ -347,7 +347,7 @@ namespace YAML return true; } - bool WriteBinary(ostream& out, const char *data, std::size_t size) + bool WriteBinary(ostream& out, const unsigned char *data, std::size_t size) { static const char encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; const char PAD = '='; diff --git a/src/emitterutils.h b/src/emitterutils.h index b6c0b70..27ca115 100644 --- a/src/emitterutils.h +++ b/src/emitterutils.h @@ -22,7 +22,7 @@ namespace YAML bool WriteAnchor(ostream& out, const std::string& str); bool WriteTag(ostream& out, const std::string& str, bool verbatim); bool WriteTagWithPrefix(ostream& out, const std::string& prefix, const std::string& tag); - bool WriteBinary(ostream& out, const char *data, std::size_t size); + bool WriteBinary(ostream& out, const unsigned char *data, std::size_t size); } } diff --git a/test/emittertests.cpp b/test/emittertests.cpp index a7c13d8..4c5c668 100644 --- a/test/emittertests.cpp +++ b/test/emittertests.cpp @@ -759,19 +759,19 @@ namespace Test void Binary(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::Binary("Hello, World!", 13); + out << YAML::Binary(reinterpret_cast("Hello, World!"), 13); desiredOutput = "!!binary \"SGVsbG8sIFdvcmxkIQ==\""; } void LongBinary(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::Binary("Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.\n", 270); + out << YAML::Binary(reinterpret_cast("Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.\n"), 270); desiredOutput = "!!binary \"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvbmx5IGJ5IGhpcyByZWFzb24sIGJ1dCBieSB0aGlzIHNpbmd1bGFyIHBhc3Npb24gZnJvbSBvdGhlciBhbmltYWxzLCB3aGljaCBpcyBhIGx1c3Qgb2YgdGhlIG1pbmQsIHRoYXQgYnkgYSBwZXJzZXZlcmFuY2Ugb2YgZGVsaWdodCBpbiB0aGUgY29udGludWVkIGFuZCBpbmRlZmF0aWdhYmxlIGdlbmVyYXRpb24gb2Yga25vd2xlZGdlLCBleGNlZWRzIHRoZSBzaG9ydCB2ZWhlbWVuY2Ugb2YgYW55IGNhcm5hbCBwbGVhc3VyZS4K\""; } void EmptyBinary(YAML::Emitter& out, std::string& desiredOutput) { - out << YAML::Binary("", 0); + out << YAML::Binary(reinterpret_cast(""), 0); desiredOutput = "!!binary \"\""; } From ae14042031d7526daf5d183604b241df689f4530 Mon Sep 17 00:00:00 2001 From: beder Date: Tue, 6 Sep 2011 01:05:14 -0500 Subject: [PATCH 293/295] Added notes about the two failing tests - that they're (I think) bugs in the YAML spec --- test/spectests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/spectests.cpp b/test/spectests.cpp index f3f05bc..185c976 100644 --- a/test/spectests.cpp +++ b/test/spectests.cpp @@ -2032,7 +2032,7 @@ namespace Test { YAML_ASSERT(doc.size() == 3); YAML_ASSERT(doc["strip"].to() == "# text"); YAML_ASSERT(doc["clip"].to() == "# text\n"); - YAML_ASSERT(doc["keep"].to() == "# text\n"); + YAML_ASSERT(doc["keep"].to() == "# text\n"); // Note: I believe this is a bug in the YAML spec - it should be "# text\n\n" return true; } @@ -2290,7 +2290,7 @@ namespace Test { PARSE(doc, input); YAML_ASSERT(doc.size() == 2); - YAML_ASSERT(doc["literal"].to() == "value"); + YAML_ASSERT(doc["literal"].to() == "value"); // Note: I believe this is a bug in the YAML spec - it should be "value\n" YAML_ASSERT(doc["folded"].to() == "value"); YAML_ASSERT(doc["folded"].Tag() == "!foo"); return true; From 138b2f473352f8426c93417ce1c1cf1d39656110 Mon Sep 17 00:00:00 2001 From: beder Date: Wed, 14 Sep 2011 01:23:15 -0500 Subject: [PATCH 294/295] Bumped version to 0.2.7 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b34518d..98a9301 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,7 +23,7 @@ project(YAML_CPP) set(YAML_CPP_VERSION_MAJOR "0") set(YAML_CPP_VERSION_MINOR "2") -set(YAML_CPP_VERSION_PATCH "6") +set(YAML_CPP_VERSION_PATCH "7") set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}") enable_testing()