From 75477ade6575fee81a8105d218f6e1924f524b8a Mon Sep 17 00:00:00 2001 From: Jesse Beder Date: Sat, 5 Sep 2009 03:49:38 +0000 Subject: [PATCH] Finished refactoring of simple keys so that they can refer to multiple tokens at a single level --- src/scanner.cpp | 19 ++++++++----- src/scanner.h | 9 ++++--- src/scantoken.cpp | 37 ++++++++++++-------------- src/simplekey.cpp | 53 +++++++++++++++++++++++++++---------- yaml-reader/parsertests.cpp | 48 +++++++++++++++++++++++++++++++++ yaml-reader/tests.cpp | 2 ++ yaml-reader/tests.h | 2 ++ 7 files changed, 126 insertions(+), 44 deletions(-) diff --git a/src/scanner.cpp b/src/scanner.cpp index 893bb31..1cadb71 100644 --- a/src/scanner.cpp +++ b/src/scanner.cpp @@ -46,7 +46,13 @@ namespace YAML assert(!m_tokens.empty()); // should we be asserting here? I mean, we really just be checking // if it's empty before peeking. -// std::cerr << "peek: (" << &m_tokens.front() << ") " << m_tokens.front() << "\n"; +#if 0 + static Token *pLast = 0; + if(pLast != &m_tokens.front()) + std::cerr << "peek: " << m_tokens.front() << "\n"; + pLast = &m_tokens.front(); +#endif + return m_tokens.front(); } @@ -98,9 +104,6 @@ namespace YAML // maybe need to end some blocks PopIndentToHere(); - // check the latest simple key - VerifySimpleKey(); - // ***** // And now branch based on the next few characters! // ***** @@ -187,7 +190,7 @@ namespace YAML INPUT.eat(n); // oh yeah, and let's get rid of that simple key - VerifySimpleKey(); + InvalidateSimpleKey(); // new line - we may be able to accept a simple key now if(m_flowLevel == 0) @@ -235,7 +238,7 @@ namespace YAML INPUT.ResetColumn(); PopAllIndents(); - VerifyAllSimpleKeys(); + PopAllSimpleKeys(); m_simpleKeyAllowed = false; m_endedStream = true; @@ -321,8 +324,10 @@ namespace YAML IndentMarker indent = m_indents.top(); IndentMarker::INDENT_TYPE type = indent.type; m_indents.pop(); - if(!indent.isValid) + if(!indent.isValid) { + InvalidateSimpleKey(); return; + } if(type == IndentMarker::SEQ) m_tokens.push(Token(Token::BLOCK_SEQ_END, INPUT.mark())); diff --git a/src/scanner.h b/src/scanner.h index d0e0135..05c79d4 100644 --- a/src/scanner.h +++ b/src/scanner.h @@ -58,9 +58,12 @@ namespace YAML int GetTopIndent() const; // checking input - void InsertSimpleKey(); - bool VerifySimpleKey(bool force = false); - void VerifyAllSimpleKeys(); + bool ExistsActiveSimpleKey() const; + void InsertPotentialSimpleKey(); + void InvalidateSimpleKey(); + bool VerifySimpleKey(); + void PopAllSimpleKeys(); + void ThrowParserException(const std::string& msg) const; bool IsWhitespaceToBeEaten(char ch); diff --git a/src/scantoken.cpp b/src/scantoken.cpp index fa853f7..0c3b983 100644 --- a/src/scantoken.cpp +++ b/src/scantoken.cpp @@ -20,7 +20,7 @@ namespace YAML // pop indents and simple keys PopAllIndents(); - VerifyAllSimpleKeys(); + PopAllSimpleKeys(); m_simpleKeyAllowed = false; @@ -60,7 +60,7 @@ namespace YAML void Scanner::ScanDocStart() { PopAllIndents(); - VerifyAllSimpleKeys(); + PopAllSimpleKeys(); m_simpleKeyAllowed = false; // eat @@ -73,7 +73,7 @@ namespace YAML void Scanner::ScanDocEnd() { PopAllIndents(); - VerifyAllSimpleKeys(); + PopAllSimpleKeys(); m_simpleKeyAllowed = false; // eat @@ -86,7 +86,7 @@ namespace YAML void Scanner::ScanFlowStart() { // flows can be simple keys - InsertSimpleKey(); + InsertPotentialSimpleKey(); m_flowLevel++; m_simpleKeyAllowed = true; @@ -103,6 +103,7 @@ namespace YAML if(m_flowLevel == 0) throw ParserException(INPUT.mark(), ErrorMsg::FLOW_END); + InvalidateSimpleKey(); m_flowLevel--; m_simpleKeyAllowed = false; @@ -170,8 +171,13 @@ namespace YAML // Value void Scanner::ScanValue() { - // does this follow a simple key? - if(m_isLastKeyValid) { + // just in case we have an empty key + InsertPotentialSimpleKey(); + + // and check that simple key + bool isSimpleKey = VerifySimpleKey(); + + if(isSimpleKey) { // can't follow a simple key with another simple key (dunno why, though - it seems fine) m_simpleKeyAllowed = false; } else { @@ -181,19 +187,10 @@ namespace YAML throw ParserException(INPUT.mark(), ErrorMsg::MAP_VALUE); PushIndentTo(INPUT.column(), IndentMarker::MAP); - } else { - // we might have an empty key, so we should add it (as a simple key) - if(m_simpleKeyAllowed) { - InsertSimpleKey(); - VerifySimpleKey(); - } } // 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 = (m_flowLevel == 0); } // eat @@ -210,7 +207,7 @@ namespace YAML // insert a potential simple key if(m_simpleKeyAllowed) - InsertSimpleKey(); + InsertPotentialSimpleKey(); m_simpleKeyAllowed = false; // eat the indicator @@ -243,7 +240,7 @@ namespace YAML // insert a potential simple key if(m_simpleKeyAllowed) - InsertSimpleKey(); + InsertPotentialSimpleKey(); m_simpleKeyAllowed = false; // eat the indicator @@ -293,7 +290,7 @@ namespace YAML // insert a potential simple key if(m_simpleKeyAllowed) - InsertSimpleKey(); + InsertPotentialSimpleKey(); Mark mark = INPUT.mark(); scalar = ScanScalar(INPUT, params); @@ -333,7 +330,7 @@ namespace YAML // insert a potential simple key if(m_simpleKeyAllowed) - InsertSimpleKey(); + InsertPotentialSimpleKey(); Mark mark = INPUT.mark(); diff --git a/src/simplekey.cpp b/src/simplekey.cpp index cf4d1b4..c8cd2bf 100644 --- a/src/simplekey.cpp +++ b/src/simplekey.cpp @@ -32,11 +32,26 @@ namespace YAML pKey->status = Token::INVALID; } - // InsertSimpleKey - // . Adds a potential simple key to the queue, - // and saves it on a stack. - void Scanner::InsertSimpleKey() + // ExistsActiveSimpleKey + // . Returns true if there's a potential simple key at our flow level + // (there's allowed at most one per flow level, i.e., at the start of the flow start token) + bool Scanner::ExistsActiveSimpleKey() const { + if(m_simpleKeys.empty()) + return false; + + const SimpleKey& key = m_simpleKeys.top(); + return key.flowLevel == m_flowLevel; + } + + // InsertPotentialSimpleKey + // . If we can, add a potential simple key to the queue, + // and save it on a stack. + void Scanner::InsertPotentialSimpleKey() + { + if(ExistsActiveSimpleKey()) + return; + SimpleKey key(INPUT.mark(), m_flowLevel); // first add a map start, if necessary @@ -55,11 +70,26 @@ namespace YAML m_simpleKeys.push(key); } + // InvalidateSimpleKey + // . Automatically invalidate the simple key in our flow level + void Scanner::InvalidateSimpleKey() + { + if(m_simpleKeys.empty()) + return; + + // grab top key + SimpleKey& key = m_simpleKeys.top(); + if(key.flowLevel != m_flowLevel) + return; + + key.Invalidate(); + m_simpleKeys.pop(); + } + // VerifySimpleKey // . Determines whether the latest simple key to be added is valid, // and if so, makes it valid. - // . If 'force' is true, then we'll pop no matter what (whether we can verify it or not). - bool Scanner::VerifySimpleKey(bool force) + bool Scanner::VerifySimpleKey() { m_isLastKeyValid = false; if(m_simpleKeys.empty()) @@ -69,11 +99,8 @@ namespace YAML SimpleKey key = m_simpleKeys.top(); // only validate if we're in the correct flow level - if(key.flowLevel != m_flowLevel) { - if(force) - m_simpleKeys.pop(); + if(key.flowLevel != m_flowLevel) return false; - } m_simpleKeys.pop(); @@ -99,11 +126,9 @@ namespace YAML return isValid; } - // VerifyAllSimplyKeys - // . Pops all simple keys (with checking, but if we can't verify one, then pop it anyways). - void Scanner::VerifyAllSimpleKeys() + void Scanner::PopAllSimpleKeys() { while(!m_simpleKeys.empty()) - VerifySimpleKey(true); + m_simpleKeys.pop(); } } diff --git a/yaml-reader/parsertests.cpp b/yaml-reader/parsertests.cpp index e3410df..aee6355 100644 --- a/yaml-reader/parsertests.cpp +++ b/yaml-reader/parsertests.cpp @@ -407,6 +407,54 @@ namespace Test return true; } + bool AnchorInSimpleKey() + { + std::string input = "- &a b: c\n- *a"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + if(doc.size() != 2) + return false; + + std::string output; + doc[0]["b"] >> output; + if(output != "c") + return false; + + doc[1] >> output; + if(output != "b") + return false; + + return true; + } + + bool AliasAsSimpleKey() + { + std::string input = "- &a b\n- *a: c"; + + std::stringstream stream(input); + YAML::Parser parser(stream); + YAML::Node doc; + parser.GetNextDocument(doc); + + if(doc.size() != 2) + return false; + + std::string output; + doc[0] >> output; + if(output != "b") + return false; + + doc[1]["b"] >> output; + if(output != "c") + return false; + + return true; + } + bool ExplicitDoc() { std::string input = "---\n- one\n- two"; diff --git a/yaml-reader/tests.cpp b/yaml-reader/tests.cpp index 8bf33ba..d727108 100644 --- a/yaml-reader/tests.cpp +++ b/yaml-reader/tests.cpp @@ -275,6 +275,8 @@ namespace Test RunParserTest(&Parser::NullBlockMapValue, "null block map value", passed); RunParserTest(&Parser::SimpleAlias, "simple alias", passed); RunParserTest(&Parser::AliasWithNull, "alias with null", passed); + RunParserTest(&Parser::AnchorInSimpleKey, "anchor in simple key", passed); + RunParserTest(&Parser::AliasAsSimpleKey, "alias as simple key", passed); RunParserTest(&Parser::ExplicitDoc, "explicit doc", passed); RunParserTest(&Parser::MultipleDocs, "multiple docs", passed); RunParserTest(&Parser::ExplicitEndDoc, "explicit end doc", passed); diff --git a/yaml-reader/tests.h b/yaml-reader/tests.h index 9aa9578..80daf18 100644 --- a/yaml-reader/tests.h +++ b/yaml-reader/tests.h @@ -42,6 +42,8 @@ namespace Test { bool NullBlockMapValue(); bool SimpleAlias(); bool AliasWithNull(); + bool AnchorInSimpleKey(); + bool AliasAsSimpleKey(); bool ExplicitDoc(); bool MultipleDocs(); bool ExplicitEndDoc();