diff options
Diffstat (limited to 'src/lib/dns/master_lexer_state.h')
-rw-r--r-- | src/lib/dns/master_lexer_state.h | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/src/lib/dns/master_lexer_state.h b/src/lib/dns/master_lexer_state.h new file mode 100644 index 0000000..d328a70 --- /dev/null +++ b/src/lib/dns/master_lexer_state.h @@ -0,0 +1,138 @@ +// Copyright (C) 2012-2020 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef MASTER_LEXER_STATE_H +#define MASTER_LEXER_STATE_H 1 + +#include <dns/master_lexer.h> + +namespace isc { +namespace dns { + +namespace master_lexer_internal { + +/// \brief Tokenization state for \c MasterLexer. +/// +/// This is a base class of classes that represent various states of a single +/// tokenization session of \c MasterLexer, i.e., the states used for a +/// single call to \c MasterLexer::getNextToken(). +/// +/// It follows the convention of the state design pattern: each derived class +/// corresponds to a specific state, and the state transition takes place +/// through the virtual method named \c handle(). The \c handle() method +/// takes the main \c MasterLexer object that holds all necessary internal +/// context, and updates it as necessary; each \c State derived class is +/// completely stateless. +/// +/// The initial transition takes place in a static method of the base class, +/// \c start(). This is mainly for implementation convenience; we need to +/// pass options given to \c MasterLexer::getNextToken() for the initial +/// state, so it makes more sense to separate the interface for the transition +/// from the initial state. +/// +/// If the whole lexer transition is completed within start(), it sets the +/// identified token and returns NULL; otherwise it returns a pointer to +/// an object of a specific state class that completes the session +/// on the call of handle(). +/// +/// As is usual in the state design pattern, the \c State class is made +/// a friend class of \c MasterLexer and can refer to its internal details. +/// This is intentional; essentially its a part of \c MasterLexer and +/// is defined as a separate class only for implementation clarity and better +/// testability. It's defined in a publicly visible header, but that's only +/// for testing purposes. No normal application or even no other classes of +/// this library are expected to use this class. +class State { +public: + /// \brief Virtual destructor. + /// + /// In our usage this actually doesn't matter, but some compilers complain + /// about it and we need to silence them. + virtual ~State() {} + + /// \brief Begin state transitions to get the next token. + /// + /// This is the first method that \c MasterLexer needs to call for a + /// tokenization session. The lexer passes a reference to itself + /// and options given in \c getNextToken(). + /// + /// \throw MasterLexer::ReadError Unexpected I/O error + /// \throw std::bad_alloc Internal resource allocation failure + /// + /// \param lexer The lexer object that holds the main context. + /// \param options The options passed to getNextToken(). + /// \return A pointer to the next state object or NULL if the transition + /// is completed. + static const State* start(MasterLexer& lexer, + MasterLexer::Options options); + + /// \brief Handle the process of one specific state. + /// + /// This method is expected to be called on the object returned by + /// start(). In the usual state transition design pattern, it would + /// return the next state. But as we noticed, we never have another + /// state, so we simplify it by not returning anything instead of + /// returning NULL every time. + /// + /// \throw MasterLexer::ReadError Unexpected I/O error + /// \throw std::bad_alloc Internal resource allocation failure + /// + /// \param lexer The lexer object that holds the main context. + virtual void handle(MasterLexer& lexer) const = 0; + + /// \brief Types of states. + /// + /// Specific states are basically hidden within the implementation, + /// but we'd like to allow tests to examine them, so we provide + /// a way to get an instance of a specific state. + enum ID { + CRLF, ///< Just seen a carriage-return character + String, ///< Handling a string token + QString, ///< Handling a quoted string token + Number ///< Handling a number + }; + + /// \brief Returns a \c State instance of the given state. + /// + /// This is provided only for testing purposes so tests can check + /// the behavior of each state separately. \c MasterLexer shouldn't + /// need this method. + static const State& getInstance(ID state_id); + + /// \name Read-only accessors for testing purposes. + /// + /// These allow tests to inspect some selected portion of the internal + /// states of \c MasterLexer. These shouldn't be used except for testing + /// purposes. + ///@{ + bool wasLastEOL(const MasterLexer& lexer) const; + const MasterToken& getToken(const MasterLexer& lexer) const; + size_t getParenCount(const MasterLexer& lexer) const; + ///@} + +protected: + /// \brief An accessor to the internal implementation class of + /// \c MasterLexer. + /// + /// This is provided for specific derived classes as they are not direct + /// friends of \c MasterLexer. + /// + /// \param lexer The lexer object that holds the main context. + /// \return A pointer to the implementation class object of the given + /// lexer. This is never NULL. + 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: |