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
void Clear();
std::auto_ptr<Node> 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;
......
......@@ -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*/)
{
}
......
......@@ -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 <Node *>::const_iterator&) const;
......
......@@ -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 <Node *>::const_iterator&) const { return false; }
......
......@@ -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 <Node> 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 <Node> 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
......
......@@ -27,7 +27,7 @@ namespace YAML
virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const;
virtual bool GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const;
virtual std::size_t GetSize() const;
virtual void Parse(Scanner *pScanner, 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;
......
......@@ -54,7 +54,7 @@ namespace YAML
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();
......@@ -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 != "")
......
......@@ -6,6 +6,8 @@
#include <string>
#include <map>
#include <stack>
#include <cassert>
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 <std::string, std::string> tags;
std::stack <COLLECTION_TYPE> collectionStack;
};
}
......
......@@ -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;
......
......@@ -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; }
......
......@@ -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
......
......@@ -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 <Node *> m_data;
......
......@@ -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);
......
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