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

Fixed bug with block maps with null value (the next key was being read as the value)

parent ecb30132
...@@ -32,7 +32,7 @@ namespace YAML ...@@ -32,7 +32,7 @@ namespace YAML
void Clear(); void Clear();
std::auto_ptr<Node> Clone() const; std::auto_ptr<Node> Clone() const;
void Parse(Scanner *pScanner, const ParserState& state); void Parse(Scanner *pScanner, ParserState& state);
CONTENT_TYPE GetType() const; CONTENT_TYPE GetType() const;
...@@ -102,10 +102,10 @@ namespace YAML ...@@ -102,10 +102,10 @@ namespace YAML
Node(const Mark& mark, const std::string& anchor, const std::string& tag, const Content *pContent); Node(const Mark& mark, const std::string& anchor, const std::string& tag, const Content *pContent);
// helpers for parsing // helpers for parsing
void ParseHeader(Scanner *pScanner, const ParserState& state); void ParseHeader(Scanner *pScanner, ParserState& state);
void ParseTag(Scanner *pScanner, const ParserState& state); void ParseTag(Scanner *pScanner, ParserState& state);
void ParseAnchor(Scanner *pScanner, const ParserState& state); void ParseAnchor(Scanner *pScanner, ParserState& state);
void ParseAlias(Scanner *pScanner, const ParserState& state); void ParseAlias(Scanner *pScanner, ParserState& state);
private: private:
Mark m_mark; Mark m_mark;
......
...@@ -12,7 +12,7 @@ namespace YAML ...@@ -12,7 +12,7 @@ namespace YAML
return 0; // TODO: how to clone an alias? return 0; // TODO: how to clone an alias?
} }
void AliasContent::Parse(Scanner * /*pScanner*/, const ParserState& /*state*/) void AliasContent::Parse(Scanner * /*pScanner*/, ParserState& /*state*/)
{ {
} }
......
...@@ -15,7 +15,7 @@ namespace YAML ...@@ -15,7 +15,7 @@ namespace YAML
virtual Content *Clone() const; 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 void Write(Emitter&) const;
virtual bool GetBegin(std::vector <Node *>::const_iterator&) const; virtual bool GetBegin(std::vector <Node *>::const_iterator&) const;
......
...@@ -28,7 +28,7 @@ namespace YAML ...@@ -28,7 +28,7 @@ namespace YAML
virtual Content *Clone() const = 0; 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 void Write(Emitter& out) const = 0;
virtual bool GetBegin(std::vector <Node *>::const_iterator&) const { return false; } virtual bool GetBegin(std::vector <Node *>::const_iterator&) const { return false; }
......
...@@ -57,7 +57,7 @@ namespace YAML ...@@ -57,7 +57,7 @@ namespace YAML
return m_data.size(); return m_data.size();
} }
void Map::Parse(Scanner *pScanner, const ParserState& state) void Map::Parse(Scanner *pScanner, ParserState& state)
{ {
Clear(); Clear();
...@@ -71,10 +71,11 @@ namespace YAML ...@@ -71,10 +71,11 @@ namespace YAML
} }
} }
void Map::ParseBlock(Scanner *pScanner, const ParserState& state) void Map::ParseBlock(Scanner *pScanner, ParserState& state)
{ {
// eat start token // eat start token
pScanner->pop(); pScanner->pop();
state.PushCollectionType(ParserState::BLOCK_MAP);
while(1) { while(1) {
if(pScanner->empty()) if(pScanner->empty())
...@@ -106,12 +107,15 @@ namespace YAML ...@@ -106,12 +107,15 @@ namespace YAML
// assign the map with the actual pointers // assign the map with the actual pointers
m_data[pKey.release()] = pValue.release(); 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 // eat start token
pScanner->pop(); pScanner->pop();
state.PushCollectionType(ParserState::FLOW_MAP);
while(1) { while(1) {
if(pScanner->empty()) if(pScanner->empty())
...@@ -148,12 +152,15 @@ namespace YAML ...@@ -148,12 +152,15 @@ namespace YAML
// assign the map with the actual pointers // assign the map with the actual pointers
m_data[pKey.release()] = pValue.release(); m_data[pKey.release()] = pValue.release();
} }
state.PopCollectionType(ParserState::FLOW_MAP);
} }
// ParseCompact // 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) void Map::ParseCompact(Scanner *pScanner, ParserState& state)
{ {
state.PushCollectionType(ParserState::COMPACT_MAP);
std::auto_ptr <Node> pKey(new Node), pValue(new Node); std::auto_ptr <Node> pKey(new Node), pValue(new Node);
// grab key // grab key
...@@ -168,12 +175,14 @@ namespace YAML ...@@ -168,12 +175,14 @@ namespace YAML
// assign the map with the actual pointers // assign the map with the actual pointers
m_data[pKey.release()] = pValue.release(); m_data[pKey.release()] = pValue.release();
state.PopCollectionType(ParserState::COMPACT_MAP);
} }
// ParseCompactWithNoKey // ParseCompactWithNoKey
// . Single ": value" pair in a flow sequence // . 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 <Node> pKey(new Node), pValue(new Node); std::auto_ptr <Node> pKey(new Node), pValue(new Node);
// grab value // grab value
...@@ -182,6 +191,7 @@ namespace YAML ...@@ -182,6 +191,7 @@ namespace YAML
// assign the map with the actual pointers // assign the map with the actual pointers
m_data[pKey.release()] = pValue.release(); m_data[pKey.release()] = pValue.release();
state.PopCollectionType(ParserState::COMPACT_MAP);
} }
void Map::Write(Emitter& out) const void Map::Write(Emitter& out) const
......
...@@ -27,7 +27,7 @@ namespace YAML ...@@ -27,7 +27,7 @@ namespace YAML
virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const; virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const;
virtual bool GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const; virtual bool GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const;
virtual std::size_t GetSize() const; virtual std::size_t GetSize() const;
virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Parse(Scanner *pScanner, ParserState& state);
virtual void Write(Emitter& out) const; virtual void Write(Emitter& out) const;
virtual bool IsMap() const { return true; } virtual bool IsMap() const { return true; }
...@@ -39,10 +39,10 @@ namespace YAML ...@@ -39,10 +39,10 @@ namespace YAML
virtual int Compare(Map *pMap); virtual int Compare(Map *pMap);
private: private:
void ParseBlock(Scanner *pScanner, const ParserState& state); void ParseBlock(Scanner *pScanner, ParserState& state);
void ParseFlow(Scanner *pScanner, const ParserState& state); void ParseFlow(Scanner *pScanner, ParserState& state);
void ParseCompact(Scanner *pScanner, const ParserState& state); void ParseCompact(Scanner *pScanner, ParserState& state);
void ParseCompactWithNoKey(Scanner *pScanner, const ParserState& state); void ParseCompactWithNoKey(Scanner *pScanner, ParserState& state);
private: private:
node_map m_data; node_map m_data;
......
...@@ -54,7 +54,7 @@ namespace YAML ...@@ -54,7 +54,7 @@ namespace YAML
return std::auto_ptr<Node> (new Node(m_mark, m_anchor, m_tag, m_pContent)); return std::auto_ptr<Node> (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(); Clear();
...@@ -104,13 +104,14 @@ namespace YAML ...@@ -104,13 +104,14 @@ namespace YAML
break; break;
case Token::FLOW_MAP_START: case Token::FLOW_MAP_START:
case Token::BLOCK_MAP_START: case Token::BLOCK_MAP_START:
case Token::KEY:
m_pContent = new Map; m_pContent = new Map;
break; break;
case Token::KEY:
// compact maps can only go in a flow sequence
if(state.GetCurCollectionType() == ParserState::FLOW_SEQ)
m_pContent = new Map;
break;
default: default:
// std::stringstream str;
// str << TokenNames[pScanner->peek().type];
// throw std::runtime_error(str.str());
break; break;
} }
...@@ -125,7 +126,7 @@ namespace YAML ...@@ -125,7 +126,7 @@ namespace YAML
// ParseHeader // ParseHeader
// . Grabs any tag, alias, or anchor tokens and deals with them. // . 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) { while(1) {
if(pScanner->empty()) if(pScanner->empty())
...@@ -140,7 +141,7 @@ namespace YAML ...@@ -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(); Token& token = pScanner->peek();
if(m_tag != "") if(m_tag != "")
...@@ -151,7 +152,7 @@ namespace YAML ...@@ -151,7 +152,7 @@ namespace YAML
pScanner->pop(); pScanner->pop();
} }
void Node::ParseAnchor(Scanner *pScanner, const ParserState& /*state*/) void Node::ParseAnchor(Scanner *pScanner, ParserState& /*state*/)
{ {
Token& token = pScanner->peek(); Token& token = pScanner->peek();
if(m_anchor != "") if(m_anchor != "")
...@@ -162,7 +163,7 @@ namespace YAML ...@@ -162,7 +163,7 @@ namespace YAML
pScanner->pop(); pScanner->pop();
} }
void Node::ParseAlias(Scanner *pScanner, const ParserState& /*state*/) void Node::ParseAlias(Scanner *pScanner, ParserState& /*state*/)
{ {
Token& token = pScanner->peek(); Token& token = pScanner->peek();
if(m_anchor != "") if(m_anchor != "")
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
#include <string> #include <string>
#include <map> #include <map>
#include <stack>
#include <cassert>
namespace YAML namespace YAML
{ {
...@@ -16,11 +18,19 @@ namespace YAML ...@@ -16,11 +18,19 @@ namespace YAML
struct ParserState struct ParserState
{ {
enum COLLECTION_TYPE { NONE, BLOCK_MAP, BLOCK_SEQ, FLOW_MAP, FLOW_SEQ, COMPACT_MAP };
ParserState(); ParserState();
const std::string TranslateTagHandle(const std::string& handle) const; 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; Version version;
std::map <std::string, std::string> tags; std::map <std::string, std::string> tags;
std::stack <COLLECTION_TYPE> collectionStack;
}; };
} }
......
...@@ -24,7 +24,7 @@ namespace YAML ...@@ -24,7 +24,7 @@ namespace YAML
return new Scalar(m_data); return new Scalar(m_data);
} }
void Scalar::Parse(Scanner *pScanner, const ParserState& /*state*/) void Scalar::Parse(Scanner *pScanner, ParserState& /*state*/)
{ {
Token& token = pScanner->peek(); Token& token = pScanner->peek();
m_data = token.value; m_data = token.value;
......
...@@ -18,7 +18,7 @@ namespace YAML ...@@ -18,7 +18,7 @@ namespace YAML
virtual Content *Clone() const; 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 void Write(Emitter& out) const;
virtual bool IsScalar() const { return true; } virtual bool IsScalar() const { return true; }
......
...@@ -59,7 +59,7 @@ namespace YAML ...@@ -59,7 +59,7 @@ namespace YAML
return m_data.size(); return m_data.size();
} }
void Sequence::Parse(Scanner *pScanner, const ParserState& state) void Sequence::Parse(Scanner *pScanner, ParserState& state)
{ {
Clear(); Clear();
...@@ -71,10 +71,11 @@ namespace YAML ...@@ -71,10 +71,11 @@ namespace YAML
} }
} }
void Sequence::ParseBlock(Scanner *pScanner, const ParserState& state) void Sequence::ParseBlock(Scanner *pScanner, ParserState& state)
{ {
// eat start token // eat start token
pScanner->pop(); pScanner->pop();
state.PushCollectionType(ParserState::BLOCK_SEQ);
while(1) { while(1) {
if(pScanner->empty()) if(pScanner->empty())
...@@ -100,12 +101,15 @@ namespace YAML ...@@ -100,12 +101,15 @@ namespace YAML
pNode->Parse(pScanner, state); 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 // eat start token
pScanner->pop(); pScanner->pop();
state.PushCollectionType(ParserState::FLOW_SEQ);
while(1) { while(1) {
if(pScanner->empty()) if(pScanner->empty())
...@@ -129,6 +133,8 @@ namespace YAML ...@@ -129,6 +133,8 @@ namespace YAML
else if(token.type != Token::FLOW_SEQ_END) else if(token.type != Token::FLOW_SEQ_END)
throw ParserException(token.mark, ErrorMsg::END_OF_SEQ_FLOW); throw ParserException(token.mark, ErrorMsg::END_OF_SEQ_FLOW);
} }
state.PopCollectionType(ParserState::FLOW_SEQ);
} }
void Sequence::Write(Emitter& out) const void Sequence::Write(Emitter& out) const
......
...@@ -26,7 +26,7 @@ namespace YAML ...@@ -26,7 +26,7 @@ namespace YAML
virtual Node *GetNode(std::size_t i) const; virtual Node *GetNode(std::size_t i) const;
virtual std::size_t GetSize() const; virtual std::size_t GetSize() const;
virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Parse(Scanner *pScanner, ParserState& state);
virtual void Write(Emitter& out) const; virtual void Write(Emitter& out) const;
virtual bool IsSequence() const { return true; } virtual bool IsSequence() const { return true; }
...@@ -38,8 +38,8 @@ namespace YAML ...@@ -38,8 +38,8 @@ namespace YAML
virtual int Compare(Map *) { return -1; } virtual int Compare(Map *) { return -1; }
private: private:
void ParseBlock(Scanner *pScanner, const ParserState& state); void ParseBlock(Scanner *pScanner, ParserState& state);
void ParseFlow(Scanner *pScanner, const ParserState& state); void ParseFlow(Scanner *pScanner, ParserState& state);
protected: protected:
std::vector <Node *> m_data; std::vector <Node *> m_data;
......
...@@ -610,6 +610,28 @@ namespace Test ...@@ -610,6 +610,28 @@ namespace Test
return true; 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 { namespace {
...@@ -869,6 +891,7 @@ namespace Test ...@@ -869,6 +891,7 @@ namespace Test
RunParserTest(&Parser::MultipleDocs, "multiple docs", passed, total); RunParserTest(&Parser::MultipleDocs, "multiple docs", passed, total);
RunParserTest(&Parser::ExplicitEndDoc, "explicit end doc", passed, total); RunParserTest(&Parser::ExplicitEndDoc, "explicit end doc", passed, total);
RunParserTest(&Parser::MultipleDocsWithSomeExplicitIndicators, "multiple docs with some explicit indicators", 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, false, "UTF-8, no BOM", passed, total);
RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed, total); RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed, total);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment