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

This commit is contained in:
Jesse Beder
2009-10-30 01:06:19 +00:00
parent ecb30132e9
commit e04be7890a
13 changed files with 85 additions and 35 deletions

View File

@@ -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;

View File

@@ -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*/)
{
}

View File

@@ -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;

View File

@@ -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; }

View File

@@ -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

View File

@@ -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;

View File

@@ -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 != "")

View File

@@ -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;
};
}

View File

@@ -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;

View File

@@ -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; }

View File

@@ -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

View File

@@ -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;

View File

@@ -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);