Commit 150c7dbb authored by JINMEI Tatuya's avatar JINMEI Tatuya

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

Fixing merge conflicts:
	src/lib/dns/master_lexer.cc
parent 2645b4f7
......@@ -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
......
......@@ -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
......@@ -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
......
// 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:
......@@ -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
......
// 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);
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment