summaryrefslogtreecommitdiffstats
path: root/src/lib/dns/master_lexer_state.h
blob: 301151bec97099b8561ca0fb3fa92501a1f01e67 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// 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>

#include <boost/function.hpp>

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.
///
/// When an object of a specific state class completes the session, it
/// normally sets the identified token in the lexer, and returns NULL;
/// if more transition is necessary, it returns a pointer to the next state
/// object.
///
/// 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 InputSource::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(), and keep called on the returned object until NULL is
    /// returned.  The call chain will form the complete state transition.
    ///
    /// \throw InputSource::ReadError Unexpected I/O error
    /// \throw std::bad_alloc Internal resource allocation failure
    ///
    /// \param lexer The lexer object that holds the main context.
    /// \return A pointer to the next state object or NULL if the transition
    /// is completed.
    virtual const State* 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
    };

    /// \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);

    /// \brief Returns a fake State instance.
    ///
    /// The returned State will eat eat_chars from the input source,
    /// it'll set the given token if not NULL, call the given callback
    /// and return the next state when its handle() is called. Also, the
    /// parentheses count is changed accordingly a the last EOL condition
    /// set if provided.
    ///
    /// This is provided only for testing purposes. MasterLexer shouldn't
    /// need this method.
    ///
    /// The caller is responsible for deleting the State.
    static State* getFakeState(const State* next, size_t eat_chars,
                               MasterLexer::Token* token = NULL,
                               int paren_change = 0,
                               const bool* set_eol = NULL,
                               const boost::function<void
                                   (const std::string&)>& callback =
                               boost::function<void (const std::string&)>());

    /// \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 MasterLexer::Token& 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: