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 {