Browse Source

[2506] added another version of getNextToken, basic part

JINMEI Tatuya 12 years ago
parent
commit
b991213a38

+ 28 - 0
src/lib/dns/master_lexer.cc

@@ -192,6 +192,34 @@ MasterLexer::getNextToken(Options options) {
     return (impl_->token_);
     return (impl_->token_);
 }
 }
 
 
+const MasterToken&
+MasterLexer::getNextToken(MasterToken::Type expect, bool eol_ok) {
+    Options options = NONE;
+    if (expect == MasterToken::QSTRING) {
+        options = options | QSTRING;
+    }
+
+    getNextToken(options);      // the result should be set in impl_->token_
+
+    const bool is_eol_like =
+        (impl_->token_.getType() == MasterToken::END_OF_LINE ||
+         impl_->token_.getType() == MasterToken::END_OF_FILE);
+    if (eol_ok && is_eol_like) {
+        return (impl_->token_);
+    }
+    if (impl_->token_.getType() == MasterToken::STRING &&
+        expect == MasterToken::QSTRING) {
+        return (impl_->token_);
+    }
+    if (impl_->token_.getType() != expect) {
+        ungetToken();
+        throw LexerError(__FILE__, __LINE__,
+                         MasterToken(MasterToken::UNEXPECTED_END));
+    }
+
+    return (impl_->token_);
+}
+
 void
 void
 MasterLexer::ungetToken() {
 MasterLexer::ungetToken() {
     if (impl_->has_previous_) {
     if (impl_->has_previous_) {

+ 12 - 0
src/lib/dns/master_lexer.h

@@ -306,6 +306,15 @@ public:
         {}
         {}
     };
     };
 
 
+    class LexerError : public Exception {
+    public:
+        LexerError(const char* file, size_t line, MasterToken error_token) :
+            Exception(file, line, error_token.getErrorText().c_str()),
+            token_(error_token)
+        {}
+        const MasterToken token_;
+    };
+
     /// \brief Options for getNextToken.
     /// \brief Options for getNextToken.
     ///
     ///
     /// A compound option, indicating multiple options are set, can be
     /// A compound option, indicating multiple options are set, can be
@@ -442,6 +451,9 @@ public:
     ///     or the token fail.
     ///     or the token fail.
     const MasterToken& getNextToken(Options options = NONE);
     const MasterToken& getNextToken(Options options = NONE);
 
 
+    const MasterToken& getNextToken(MasterToken::Type expect,
+                                    bool eol_ok = false);
+
     /// \brief Return the last token back to the lexer.
     /// \brief Return the last token back to the lexer.
     ///
     ///
     /// The method undoes the lasts call to getNextToken(). If you call the
     /// The method undoes the lasts call to getNextToken(). If you call the

+ 72 - 0
src/lib/dns/tests/master_lexer_unittest.cc

@@ -284,4 +284,76 @@ TEST_F(MasterLexerTest, ungetAfterSwitch) {
     EXPECT_THROW(lexer.ungetToken(), isc::InvalidOperation);
     EXPECT_THROW(lexer.ungetToken(), isc::InvalidOperation);
 }
 }
 
 
+// Common checks regarding expected/unexpected end-of-line
+void
+eolCheck(MasterLexer& lexer, MasterToken::Type expect) {
+    // If EOL is found and eol_ok is true, we get it.
+    EXPECT_EQ(MasterToken::END_OF_LINE,
+              lexer.getNextToken(expect, true).getType());
+    // We'll see the second '\n'; by default it will fail.
+    EXPECT_THROW(lexer.getNextToken(expect), MasterLexer::LexerError);
+    // Same if eol_ok is explicitly set to false.  This also checks the
+    // offending '\n' was "ungotten".
+    EXPECT_THROW(lexer.getNextToken(expect, false), MasterLexer::LexerError);
+
+    // And also check the error token set in the exception object.
+    bool thrown = false;
+    try {
+        lexer.getNextToken(expect);
+    } catch (const MasterLexer::LexerError& error) {
+        EXPECT_EQ(MasterToken::UNEXPECTED_END, error.token_.getErrorCode());
+        thrown = true;
+    }
+    EXPECT_TRUE(thrown);
+}
+
+// Common checks regarding expected/unexpected end-of-file
+void
+eofCheck(MasterLexer& lexer, MasterToken::Type expect) {
+    EXPECT_EQ(MasterToken::END_OF_FILE,
+              lexer.getNextToken(expect, true).getType());
+    EXPECT_THROW(lexer.getNextToken(expect), MasterLexer::LexerError);
+    EXPECT_THROW(lexer.getNextToken(expect, false), MasterLexer::LexerError);
+}
+
+TEST_F(MasterLexerTest, getNextTokenString) {
+    ss << "normal-string\n";
+    ss << "\n";
+    ss << "another-string";
+    lexer.pushSource(ss);
+
+    // Normal successful case: Expecting a string and get one.
+    EXPECT_EQ("normal-string",
+              lexer.getNextToken(MasterToken::STRING).getString());
+    eolCheck(lexer, MasterToken::STRING);
+
+    // Skip the 2nd '\n'
+    EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
+
+    // Same set of tests but for end-of-file
+    EXPECT_EQ("another-string",
+              lexer.getNextToken(MasterToken::STRING, true).getString());
+    eofCheck(lexer, MasterToken::STRING);
+}
+
+TEST_F(MasterLexerTest, getNextTokenQString) {
+    ss << "\"quoted-string\"\n";
+    ss << "\n";
+    ss << "normal-string";
+    lexer.pushSource(ss);
+
+    // Expecting a quoted string and get one.
+    EXPECT_EQ("quoted-string",
+              lexer.getNextToken(MasterToken::QSTRING).getString());
+    eolCheck(lexer, MasterToken::QSTRING);
+
+    // Skip the 2nd '\n'
+    EXPECT_EQ(MasterToken::END_OF_LINE, lexer.getNextToken().getType());
+
+    // Expecting a quoted string but see a normal string.  It's okay.
+    EXPECT_EQ("normal-string",
+              lexer.getNextToken(MasterToken::QSTRING).getString());
+    eofCheck(lexer, MasterToken::QSTRING);
+}
+
 }
 }