Browse Source

[2372] lexer state classes, some initial defs and tests

Fixing merge conflicts:
	src/lib/dns/master_lexer.cc
JINMEI Tatuya 12 years ago
parent
commit
150c7dbba7

+ 1 - 0
src/lib/dns/Makefile.am

@@ -97,6 +97,7 @@ libb10_dns___la_SOURCES += master_lexer_inputsource.h master_lexer_inputsource.c
 libb10_dns___la_SOURCES += labelsequence.h labelsequence.cc
 libb10_dns___la_SOURCES += masterload.h masterload.cc
 libb10_dns___la_SOURCES += master_lexer.h master_lexer.cc
+libb10_dns___la_SOURCES += master_lexer_state.h
 libb10_dns___la_SOURCES += message.h message.cc
 libb10_dns___la_SOURCES += messagerenderer.h messagerenderer.cc
 libb10_dns___la_SOURCES += name.h name.cc

+ 64 - 1
src/lib/dns/master_lexer.cc

@@ -16,6 +16,7 @@
 
 #include <dns/master_lexer.h>
 #include <dns/master_lexer_inputsource.h>
+#include <dns/master_lexer_state.h>
 
 #include <boost/shared_ptr.hpp>
 
@@ -33,9 +34,13 @@ typedef boost::shared_ptr<master_lexer_internal::InputSource> InputSourcePtr;
 using namespace master_lexer_internal;
 
 struct MasterLexer::MasterLexerImpl {
-    MasterLexerImpl() : token_(Token::NOT_STARTED) {}
+    MasterLexerImpl() : source_(NULL), last_was_eol_(false),
+                        token_(Token::NOT_STARTED)
+    {}
 
     std::vector<InputSourcePtr> sources_;
+    InputSource* source_;       // current source
+    bool last_was_eol_;
     Token token_;
 };
 
@@ -61,12 +66,15 @@ MasterLexer::pushSource(const char* filename, std::string* error) {
         return (false);
     }
 
+    impl_->sources_.push_back(InputSourcePtr(new InputSource(filename)));
+    impl_->source_ = impl_->sources_.back().get();
     return (true);
 }
 
 void
 MasterLexer::pushSource(std::istream& input) {
     impl_->sources_.push_back(InputSourcePtr(new InputSource(input)));
+    impl_->source_ = impl_->sources_.back().get();
 }
 
 void
@@ -76,6 +84,8 @@ MasterLexer::popSource() {
                   "MasterLexer::popSource on an empty source");
     }
     impl_->sources_.pop_back();
+    impl_->source_ = impl_->sources_.empty() ? NULL :
+        impl_->sources_.back().get();
 }
 
 std::string
@@ -116,5 +126,58 @@ MasterLexer::Token::getErrorText() const {
     return (error_text[val_.error_code_]);
 }
 
+namespace master_lexer_internal {
+typedef MasterLexer::Token Token; // convenience shortcut
+
+bool
+State::wasLastEOL(MasterLexer& lexer) const {
+    return (lexer.impl_->last_was_eol_);
+}
+
+const MasterLexer::Token
+State::getToken(MasterLexer& lexer) const {
+    return (lexer.impl_->token_);
+}
+
+class Start : public State {
+public:
+    Start() {}
+    virtual const State* handle(MasterLexer& lexer) const {
+        const int c = getLexerImpl(lexer)->source_->getChar();
+        if (c < 0) {
+            // TODO: handle unbalance cases
+            getLexerImpl(lexer)->last_was_eol_ = false;
+            getLexerImpl(lexer)->token_ = Token(Token::END_OF_FILE);
+            return (NULL);
+        } else if (c == '\n') {
+            getLexerImpl(lexer)->last_was_eol_ = true;
+            getLexerImpl(lexer)->token_ = Token(Token::END_OF_LINE);
+            return (NULL);
+        }
+        return (&State::getInstance(State::CRLF)); // placeholder
+    }
+};
+
+class CRLF : public State {
+public:
+    CRLF() {}
+    virtual const State* handle(MasterLexer& /*lexer*/) const {
+        return (NULL);
+    }
+};
+
+namespace {
+const Start START_STATE;
+const CRLF CRLF_STARTE;
+}
+
+const State&
+State::getInstance(ID /*state_id*/) {
+    return (START_STATE);
+}
+
+
+} // namespace master_lexer_internal
+
 } // end of namespace dns
 } // end of namespace isc

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

@@ -24,6 +24,9 @@
 
 namespace isc {
 namespace dns {
+namespace master_lexer_internal {
+class State;
+}
 
 /// \brief Tokenizer for parsing DNS master files.
 ///
@@ -43,6 +46,7 @@ namespace dns {
 /// specifically by the \c MasterLoader class and \c Rdata implementation
 /// classes.
 class MasterLexer {
+    friend class master_lexer_internal::State;
 public:
     class Token;       // we define it separately for better readability
 

+ 54 - 0
src/lib/dns/master_lexer_state.h

@@ -0,0 +1,54 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef MASTER_LEXER_STATE_H
+#define MASTER_LEXER_STATE_H 1
+
+#include <dns/master_lexer.h>
+
+namespace isc {
+namespace dns {
+
+namespace master_lexer_internal {
+class InputSource;
+
+class State {
+public:
+    enum ID {
+        Start,                  ///< TBD
+        CRLF,
+        EatLine
+    };
+    virtual const State* handle(MasterLexer& lexer) const = 0;
+
+    static const State& getInstance(ID state_id);
+
+    /// \name Read-only accessors for testing purposes.
+    bool wasLastEOL(MasterLexer& lexer) const;
+    const MasterLexer::Token getToken(MasterLexer& lexer) const;
+
+protected:
+    MasterLexer::MasterLexerImpl* getLexerImpl(MasterLexer& lexer) const {
+        return (lexer.impl_);
+    }
+};
+
+} // namespace master_lexer_internal
+} // namespace dns
+} // namespace isc
+#endif  // MASTER_LEXER_STATE_H
+
+// Local Variables:
+// mode: c++
+// End:

+ 1 - 0
src/lib/dns/tests/Makefile.am

@@ -27,6 +27,7 @@ run_unittests_SOURCES += labelsequence_unittest.cc
 run_unittests_SOURCES += messagerenderer_unittest.cc
 run_unittests_SOURCES += master_lexer_token_unittest.cc
 run_unittests_SOURCES += master_lexer_unittest.cc
+run_unittests_SOURCES += master_lexer_state_unittest.cc
 run_unittests_SOURCES += name_unittest.cc
 run_unittests_SOURCES += nsec3hash_unittest.cc
 run_unittests_SOURCES += rrclass_unittest.cc rrtype_unittest.cc

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

@@ -0,0 +1,72 @@
+// Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <dns/inputsource.h>
+#include <dns/master_lexer.h>
+#include <dns/master_lexer_state.h>
+
+#include <gtest/gtest.h>
+
+#include <sstream>
+
+using namespace isc::dns;
+using namespace master_lexer_internal;
+
+namespace {
+typedef MasterLexer::Token Token; // shortcut
+
+class MasterLexerStateTest : public ::testing::Test {
+protected:
+    MasterLexerStateTest() : s_start(State::getInstance(State::Start)),
+                             s_crlf(State::getInstance(State::CRLF))
+    {
+        lexer.open(ss);
+    }
+    const State& s_start;
+    const State& s_crlf;
+    MasterLexer lexer;
+    std::stringstream ss;
+};
+
+// Common check for the end-of-file condition.
+// Token is set to END_OF_FILE, and the lexer was NOT last eol state.
+// Passed state can be any valid one; they are stateless, just providing the
+// interface for inspection.
+void
+eofCheck(const State& state, MasterLexer& lexer) {
+    EXPECT_EQ(Token::END_OF_FILE, state.getToken(lexer).getType());
+    EXPECT_FALSE(state.wasLastEOL(lexer));
+}
+
+TEST_F(MasterLexerStateTest, startAndEnd) {
+    // A simple case: the input is empty, so we begin with start and
+    // are immediately done.
+    const State* s_next = s_start.handle(lexer);
+    EXPECT_EQ(static_cast<const State*>(NULL), s_next);
+    eofCheck(s_start, lexer);
+}
+
+TEST_F(MasterLexerStateTest, startToEOL) {
+    ss << "\n";
+    const State* s_next = s_start.handle(lexer);
+    EXPECT_EQ(static_cast<const State*>(NULL), s_next);
+    EXPECT_TRUE(s_start.wasLastEOL(lexer));
+    EXPECT_EQ(Token::END_OF_LINE, s_start.getToken(lexer).getType());
+
+    // The next lexer session will reach EOF.  Same eof check should pass.
+    s_start.handle(lexer);
+    eofCheck(s_start, lexer);
+}
+
+}