mirror of
https://github.com/jbeder/yaml-cpp.git
synced 2025-09-09 12:41:17 +00:00
Allowed solo entries in a flow map to be read as keys with null value
This commit is contained in:
@@ -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
|
||||
|
@@ -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 <SimpleKey> m_simpleKeys;
|
||||
std::stack <IndentMarker> m_indents;
|
||||
std::stack <FLOW_MARKER> m_flows;
|
||||
std::map <std::string, const Node *> m_anchors;
|
||||
};
|
||||
}
|
||||
|
@@ -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();
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user