forked from heavyai/heavydb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCommandResolutionChain.h
212 lines (187 loc) · 8.24 KB
/
CommandResolutionChain.h
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#ifndef COMMAND_RESOLUTION_CHAIN_H
#define COMMAND_RESOLUTION_CHAIN_H
#include "CommandDeterminant.h"
#include "InputTokenizers.h"
#include "gtest/gtest.h"
#include <sstream>
#include <vector>
template <template <typename> class INPUT_PARSER_TYPE = QuotedInputSupportParser,
template <typename> class REGEX_INPUT_PARSER_TYPE = DefaultInputParser>
class CommandResolutionChain {
public:
FRIEND_TEST(OmniSQLTest, CommandResolutionChain_DefaultTokenizer);
using CommandTokenList = std::vector<std::string>;
using ParamCountType = CommandTokenList::size_type;
using StandardTokenExtractor = INPUT_PARSER_TYPE<CommandTokenList>;
using RegexTokenExtractor = REGEX_INPUT_PARSER_TYPE<CommandTokenList>;
CommandResolutionChain(CommandResolutionChain const&) = delete;
CommandResolutionChain() = delete;
CommandResolutionChain& operator=(CommandResolutionChain const&) = delete;
template <typename RESOLUTION_FUNCTOR>
CommandResolutionChain(char const* command_line,
std::string const& target_command,
ParamCountType min_param_count,
ParamCountType max_param_count,
RESOLUTION_FUNCTOR resolution_op,
std::string const& custom_help,
std::ostream& output_stream = std::cout)
: m_resolved(false), m_output_stream(output_stream) {
extractTokens(command_line);
resolve_command(target_command,
min_param_count,
max_param_count,
resolution_op,
custom_help_string(
target_command, min_param_count, max_param_count, custom_help));
}
template <typename RESOLUTION_FUNCTOR>
CommandResolutionChain(char const* command_line,
std::string const& target_command,
ParamCountType min_param_count,
ParamCountType max_param_count,
RESOLUTION_FUNCTOR resolution_op,
std::ostream& output_stream = std::cout)
: m_resolved(false), m_output_stream(output_stream) {
extractTokens(command_line);
resolve_command(
target_command,
min_param_count,
max_param_count,
resolution_op,
default_help_string(target_command, min_param_count, max_param_count));
}
template <typename RESOLUTION_FUNCTOR>
CommandResolutionChain& operator()(std::string const& target_command,
ParamCountType min_param_count,
ParamCountType max_param_count,
RESOLUTION_FUNCTOR resolution_op,
std::string const& custom_help) {
if (m_resolved == true) {
return (*this);
}
resolve_command(target_command,
min_param_count,
max_param_count,
resolution_op,
custom_help_string(
target_command, min_param_count, max_param_count, custom_help));
return (*this);
}
template <typename RESOLUTION_FUNCTOR>
CommandResolutionChain& operator()(std::string const& target_command,
ParamCountType min_param_count,
ParamCountType max_param_count,
RESOLUTION_FUNCTOR resolution_op) {
if (m_resolved == true) {
return (*this);
}
resolve_command(
target_command,
min_param_count,
max_param_count,
resolution_op,
default_help_string(target_command, min_param_count, max_param_count));
return (*this);
}
bool is_resolved() { return m_resolved; }
private:
// Tag Dispatching Constructs
struct LambdaSelector {};
struct FunctorSelector {};
struct RegexCommandSelector {};
struct StandardCommandSelector {};
void extractTokens(char const* command_line) {
m_command_token_list = StandardTokenExtractor().extract_tokens(command_line);
m_regex_command_token_list = RegexTokenExtractor().extract_tokens(command_line);
}
std::string custom_help_string(std::string const& target_command,
ParamCountType min_param_count,
ParamCountType max_param_count,
std::string const& custom_help) {
std::ostringstream help_stream;
if (min_param_count == max_param_count) {
help_stream << target_command << " incorrect number of parameters provided; need "
<< min_param_count - 1 << " total parameter(s)\n"
<< custom_help << std::endl;
} else {
help_stream << target_command
<< " incorrect number of parameters provided; need between "
<< min_param_count - 1 << " and " << max_param_count - 1
<< " total parameter(s)\n"
<< custom_help << std::endl;
}
return help_stream.str();
}
std::string default_help_string(std::string const& target_command,
ParamCountType min_param_count,
ParamCountType max_param_count) {
std::ostringstream help_stream;
if (min_param_count == max_param_count) {
help_stream << target_command << " incorrect number of parameters provided; need "
<< min_param_count - 1 << " total parameter(s)" << std::endl;
} else {
help_stream << target_command
<< " incorrect number of parameters provided; need between "
<< min_param_count - 1 << " and " << max_param_count - 1
<< " total parameter(s)" << std::endl;
}
return help_stream.str();
}
template <typename RESOLUTION_MECHANISM>
void resolve_command(std::string const& target_command,
ParamCountType min_param_count,
ParamCountType max_param_count,
RESOLUTION_MECHANISM resolution_op,
std::string const& help_info) {
using SelectorType = typename std::conditional<
std::is_base_of<CmdDeterminant, RESOLUTION_MECHANISM>::value,
FunctorSelector,
LambdaSelector>::type;
if (m_command_token_list.empty()) {
m_resolved = true;
} else if (m_command_token_list[0] == target_command) {
if (std::is_base_of<RegexCmdDeterminant, RESOLUTION_MECHANISM>::value) {
// Regexes have an optional parameter; therefore parameter counts can vary
// And we know the count is at least one, in this branch
execute_functor_resolution_op(resolution_op, SelectorType());
} else {
if (m_command_token_list.size() < min_param_count ||
m_command_token_list.size() > max_param_count) {
m_output_stream << help_info << '\n';
} else {
execute_functor_resolution_op(resolution_op, SelectorType());
}
}
m_resolved = true;
}
}
template <typename RESOLUTION_LAMBDA>
void execute_functor_resolution_op(RESOLUTION_LAMBDA resolution_op,
LambdaSelector const&) {
resolution_op(m_command_token_list);
}
template <typename RESOLUTION_FUNCTOR>
void execute_functor_resolution_op(RESOLUTION_FUNCTOR resolution_op,
FunctorSelector const&) {
using CommandSelectorType = typename std::conditional<
std::is_base_of<RegexCmdDeterminant, RESOLUTION_FUNCTOR>::value,
RegexCommandSelector,
StandardCommandSelector>::type;
execute_regex_aware_resolution_op(resolution_op, CommandSelectorType());
}
template <typename RESOLUTION_FUNCTOR>
void execute_regex_aware_resolution_op(RESOLUTION_FUNCTOR resolution_op,
RegexCommandSelector const&) {
resolution_op(m_regex_command_token_list, m_output_stream);
}
template <typename RESOLUTION_FUNCTOR>
void execute_regex_aware_resolution_op(RESOLUTION_FUNCTOR resolution_op,
StandardCommandSelector const&) {
resolution_op(m_command_token_list, m_output_stream);
}
CommandTokenList m_command_token_list;
CommandTokenList m_regex_command_token_list;
bool m_resolved;
std::ostream& m_output_stream;
};
#endif