blob: fede04c0ab87c2247bb21fcd793c3785c95c45f1 [file] [log] [blame]
Václav Kubernát0a2a2e82018-05-11 13:59:12 +02001/*
2 * Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/
3 * Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/
4 *
5 * Written by Václav Kubernát <kubervac@fit.cvut.cz>
6 *
7*/
8
9#pragma once
Václav Kubernát195eeea2018-05-18 13:52:36 +020010
Václav Kubernát57272422019-02-08 12:48:24 +010011#include <boost/mpl/for_each.hpp>
12#include "ast_commands.hpp"
Václav Kubernát195eeea2018-05-18 13:52:36 +020013#include "parser_context.hpp"
Václav Kubernát48fc3832018-05-28 14:21:22 +020014#include "schema.hpp"
Václav Kubernátebca2552018-06-08 19:06:02 +020015#include "utils.hpp"
Václav Kubernát329c6c32019-02-06 16:41:53 +010016namespace x3 = boost::spirit::x3;
17
18struct parser_context_tag;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020019
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020020struct keyValue_class {
21 template <typename T, typename Iterator, typename Context>
22 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
23 {
24 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát48fc3832018-05-28 14:21:22 +020025 const Schema& schema = parserContext.m_schema;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020026
27 if (parserContext.m_tmpListKeys.find(ast.first) != parserContext.m_tmpListKeys.end()) {
28 _pass(context) = false;
29 parserContext.m_errorMsg = "Key \"" + ast.first + "\" was entered more than once.";
Václav Kubernát744f57f2018-06-29 22:46:26 +020030 } else if (!schema.listHasKey(parserContext.m_curPath, {parserContext.m_curModule, parserContext.m_tmpListName}, ast.first)) {
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020031 _pass(context) = false;
32 parserContext.m_errorMsg = parserContext.m_tmpListName + " is not indexed by \"" + ast.first + "\".";
Václav Kubernát41378452018-06-06 16:29:40 +020033 } else {
34 parserContext.m_tmpListKeys.insert(ast.first);
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020035 }
36 }
Václav Kubernát41378452018-06-06 16:29:40 +020037
38 template <typename Iterator, typename Exception, typename Context>
39 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
40 {
41 auto& parserContext = x3::get<parser_context_tag>(context);
42 parserContext.m_errorMsg = "Error parsing key values here:";
43 return x3::error_handler_result::rethrow;
44 }
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020045};
Václav Kubernát41378452018-06-06 16:29:40 +020046
Václav Kubernát744f57f2018-06-29 22:46:26 +020047struct node_identifier_class {
48 template <typename T, typename Iterator, typename Context>
49 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
50 {
51 auto& parserContext = x3::get<parser_context_tag>(context);
52
53 if (!parserContext.m_topLevelModulePresent) {
54 if (parserContext.m_errorMsg.empty())
55 parserContext.m_errorMsg = "You have to specify a top level module.";
56 _pass(context) = false;
57 }
58 }
59};
60
Václav Kubernát89728d82018-09-13 16:28:28 +020061struct key_identifier_class;
62
Václav Kubernát744f57f2018-06-29 22:46:26 +020063struct module_identifier_class;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020064
65struct listPrefix_class {
66 template <typename T, typename Iterator, typename Context>
67 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
68 {
69 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát48fc3832018-05-28 14:21:22 +020070 const Schema& schema = parserContext.m_schema;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020071
Václav Kubernát744f57f2018-06-29 22:46:26 +020072 if (schema.isList(parserContext.m_curPath, {parserContext.m_curModule, ast})) {
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020073 parserContext.m_tmpListName = ast;
74 } else {
75 _pass(context) = false;
76 }
77 }
78};
79
80struct listSuffix_class {
81 template <typename T, typename Iterator, typename Context>
82 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
83 {
84 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát48fc3832018-05-28 14:21:22 +020085 const Schema& schema = parserContext.m_schema;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020086
Václav Kubernát744f57f2018-06-29 22:46:26 +020087 const auto& keysNeeded = schema.listKeys(parserContext.m_curPath, {parserContext.m_curModule, parserContext.m_tmpListName});
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020088 std::set<std::string> keysSupplied;
89 for (const auto& it : ast)
90 keysSupplied.insert(it.first);
91
92 if (keysNeeded != keysSupplied) {
93 parserContext.m_errorMsg = "Not enough keys for " + parserContext.m_tmpListName + ". " +
94 "These keys were not supplied:";
95 std::set<std::string> missingKeys;
96 std::set_difference(keysNeeded.begin(), keysNeeded.end(),
97 keysSupplied.begin(), keysSupplied.end(),
98 std::inserter(missingKeys, missingKeys.end()));
99
100 for (const auto& it : missingKeys)
101 parserContext.m_errorMsg += " " + it;
102 parserContext.m_errorMsg += ".";
103
104 _pass(context) = false;
105 }
106 }
Václav Kubernát41378452018-06-06 16:29:40 +0200107
108 template <typename Iterator, typename Exception, typename Context>
109 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
110 {
111 auto& parserContext = x3::get<parser_context_tag>(context);
112 if (parserContext.m_errorMsg.empty())
113 parserContext.m_errorMsg = "Expecting ']' here:";
114 return x3::error_handler_result::rethrow;
Václav Kubernát41378452018-06-06 16:29:40 +0200115 }
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200116};
117struct listElement_class {
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200118 template <typename Iterator, typename Exception, typename Context>
Václav Kubernát41378452018-06-06 16:29:40 +0200119 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200120 {
121 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát41378452018-06-06 16:29:40 +0200122 if (parserContext.m_errorMsg.empty()) {
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200123 return x3::error_handler_result::fail;
Václav Kubernát41378452018-06-06 16:29:40 +0200124 } else {
125 return x3::error_handler_result::rethrow;
126 }
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200127 }
128};
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200129struct list_class {
130 template <typename T, typename Iterator, typename Context>
131 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
132 {
133 auto& parserContext = x3::get<parser_context_tag>(context);
134 const Schema& schema = parserContext.m_schema;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200135
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200136 if (!schema.isList(parserContext.m_curPath, {parserContext.m_curModule, ast.m_name})) {
137 _pass(context) = false;
138 }
139 }
140};
Václav Kubernát60d6f292018-05-25 09:45:32 +0200141struct nodeup_class {
142 template <typename T, typename Iterator, typename Context>
143 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
144 {
145 auto& parserContext = x3::get<parser_context_tag>(context);
146
Václav Kubernát744f57f2018-06-29 22:46:26 +0200147 if (parserContext.m_curPath.m_nodes.empty())
Václav Kubernát60d6f292018-05-25 09:45:32 +0200148 _pass(context) = false;
Václav Kubernát60d6f292018-05-25 09:45:32 +0200149 }
150};
151
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200152struct container_class {
153 template <typename T, typename Iterator, typename Context>
154 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
155 {
156 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát48fc3832018-05-28 14:21:22 +0200157 const auto& schema = parserContext.m_schema;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200158
Václav Kubernát744f57f2018-06-29 22:46:26 +0200159 if (!schema.isContainer(parserContext.m_curPath, {parserContext.m_curModule, ast.m_name}))
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200160 _pass(context) = false;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200161 }
162};
163
Václav Kubernát07204242018-06-04 18:12:09 +0200164struct leaf_class {
165 template <typename T, typename Iterator, typename Context>
166 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
167 {
168 auto& parserContext = x3::get<parser_context_tag>(context);
169 const auto& schema = parserContext.m_schema;
170
Václav Kubernát744f57f2018-06-29 22:46:26 +0200171 if (!schema.isLeaf(parserContext.m_curPath, {parserContext.m_curModule, ast.m_name}))
172 _pass(context) = false;
173 }
174};
175
Václav Kubernát744f57f2018-06-29 22:46:26 +0200176struct module_class {
177 template <typename T, typename Iterator, typename Context>
178 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
179 {
180 auto& parserContext = x3::get<parser_context_tag>(context);
181 const auto& schema = parserContext.m_schema;
182
183 if (schema.isModule(parserContext.m_curPath, ast.m_name)) {
184 parserContext.m_curModule = ast.m_name;
185 parserContext.m_topLevelModulePresent = true;
Václav Kubernát07204242018-06-04 18:12:09 +0200186 } else {
Václav Kubernát744f57f2018-06-29 22:46:26 +0200187 parserContext.m_errorMsg = "Invalid module name.";
Václav Kubernát07204242018-06-04 18:12:09 +0200188 _pass(context) = false;
189 }
190 }
191};
192
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200193struct schemaNode_class {
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200194 template <typename T, typename Iterator, typename Context>
Václav Kubernát744f57f2018-06-29 22:46:26 +0200195 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200196 {
Václav Kubernát744f57f2018-06-29 22:46:26 +0200197 auto& parserContext = x3::get<parser_context_tag>(context);
198 if (ast.m_suffix.type() == typeid(nodeup_)) {
199 parserContext.m_curPath.m_nodes.pop_back();
200 if (parserContext.m_curPath.m_nodes.empty())
201 parserContext.m_topLevelModulePresent = false;
202 } else {
203 parserContext.m_curPath.m_nodes.push_back(ast);
204 parserContext.m_curModule = boost::none;
205 }
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200206 }
Václav Kubernát744f57f2018-06-29 22:46:26 +0200207};
Václav Kubernát07204242018-06-04 18:12:09 +0200208
Václav Kubernát39ae9592019-02-05 17:35:16 +0100209struct dataNodeList_class {
210 template <typename T, typename Iterator, typename Context>
211 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
212 {
213 auto& parserContext = x3::get<parser_context_tag>(context);
214 parserContext.m_curPath.m_nodes.push_back(dataNodeToSchemaNode(ast));
215 }
216};
Václav Kubernát5c75b252018-10-10 18:33:47 +0200217
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200218struct dataNode_class {
219 template <typename T, typename Iterator, typename Context>
220 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
221 {
222 auto& parserContext = x3::get<parser_context_tag>(context);
223 if (ast.m_suffix.type() == typeid(nodeup_)) {
224 parserContext.m_curPath.m_nodes.pop_back();
225 if (parserContext.m_curPath.m_nodes.empty())
226 parserContext.m_topLevelModulePresent = false;
227 } else {
228 parserContext.m_curPath.m_nodes.push_back(dataNodeToSchemaNode(ast));
229 parserContext.m_curModule = boost::none;
230 }
231 }
232};
233
Václav Kubernát37171a12018-08-31 17:01:48 +0200234struct absoluteStart_class {
235 template <typename T, typename Iterator, typename Context>
236 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
237 {
238 auto& parserContext = x3::get<parser_context_tag>(context);
239 parserContext.m_curPath.m_nodes.clear();
Václav Kubernátb9621052019-03-18 18:27:49 +0100240 parserContext.m_topLevelModulePresent = false;
Václav Kubernát37171a12018-08-31 17:01:48 +0200241 }
242};
243
Václav Kubernát5c75b252018-10-10 18:33:47 +0200244struct dataNodesListEnd_class;
245
246struct dataPathListEnd_class;
247
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200248struct dataPath_class {
249 template <typename Iterator, typename Exception, typename Context>
250 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
251 {
252 auto& parserContext = x3::get<parser_context_tag>(context);
253 if (parserContext.m_errorMsg.empty()) {
254 parserContext.m_errorMsg = "Expected path.";
255 return x3::error_handler_result::fail;
256 } else {
257 return x3::error_handler_result::rethrow;
258 }
259 }
260};
261
262struct schemaPath_class {
Václav Kubernát07204242018-06-04 18:12:09 +0200263 template <typename Iterator, typename Exception, typename Context>
Václav Kubernát41378452018-06-06 16:29:40 +0200264 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
Václav Kubernát07204242018-06-04 18:12:09 +0200265 {
266 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát41378452018-06-06 16:29:40 +0200267 if (parserContext.m_errorMsg.empty()) {
268 parserContext.m_errorMsg = "Expected path.";
Václav Kubernát07204242018-06-04 18:12:09 +0200269 return x3::error_handler_result::fail;
Václav Kubernát41378452018-06-06 16:29:40 +0200270 } else {
271 return x3::error_handler_result::rethrow;
272 }
Václav Kubernát07204242018-06-04 18:12:09 +0200273 }
274};
275
Václav Kubernát6d791432018-10-25 16:00:35 +0200276struct discard_class;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200277
Václav Kubernát11afac72018-07-18 14:59:53 +0200278struct ls_class;
279
Václav Kubernát744f57f2018-06-29 22:46:26 +0200280struct cd_class {
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200281 template <typename Iterator, typename Exception, typename Context>
282 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const& x, Context const& context)
283 {
284 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát41378452018-06-06 16:29:40 +0200285 if (parserContext.m_errorMsg.empty())
286 parserContext.m_errorMsg = "Expected " + x.which() + " here:";
287 return x3::error_handler_result::rethrow;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200288 }
289};
Václav Kubernátb61336d2018-05-28 17:35:03 +0200290
Václav Kubernát6797df02019-03-18 20:21:50 +0100291struct presenceContainerPath_class {
Václav Kubernátb61336d2018-05-28 17:35:03 +0200292 template <typename T, typename Iterator, typename Context>
293 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
294 {
295 auto& parserContext = x3::get<parser_context_tag>(context);
296 const auto& schema = parserContext.m_schema;
297 try {
Václav Kubernát744f57f2018-06-29 22:46:26 +0200298 boost::optional<std::string> module;
Václav Kubernát6797df02019-03-18 20:21:50 +0100299 if (ast.m_nodes.back().m_prefix)
300 module = ast.m_nodes.back().m_prefix.value().m_name;
301 container_ cont = boost::get<container_>(ast.m_nodes.back().m_suffix);
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200302 schemaPath_ location = pathWithoutLastNode(parserContext.m_curPath);
Václav Kubernátb61336d2018-05-28 17:35:03 +0200303
Václav Kubernát744f57f2018-06-29 22:46:26 +0200304 if (!schema.isPresenceContainer(location, {module, cont.m_name})) {
Václav Kubernát41378452018-06-06 16:29:40 +0200305 parserContext.m_errorMsg = "This container is not a presence container.";
Václav Kubernátb61336d2018-05-28 17:35:03 +0200306 _pass(context) = false;
Václav Kubernátb61336d2018-05-28 17:35:03 +0200307 }
308 } catch (boost::bad_get&) {
Václav Kubernát41378452018-06-06 16:29:40 +0200309 parserContext.m_errorMsg = "This is not a container.";
Václav Kubernátb61336d2018-05-28 17:35:03 +0200310 _pass(context) = false;
Václav Kubernátb61336d2018-05-28 17:35:03 +0200311 }
312 }
Václav Kubernát6797df02019-03-18 20:21:50 +0100313};
Václav Kubernátb61336d2018-05-28 17:35:03 +0200314
Václav Kubernátf5f64f02019-03-19 17:15:47 +0100315struct listInstancePath_class {
316 template <typename T, typename Iterator, typename Context>
317 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
318 {
319 auto& parserContext = x3::get<parser_context_tag>(context);
320 if (ast.m_nodes.back().m_suffix.type() != typeid(listElement_)) {
321 parserContext.m_errorMsg = "This is not a list instance.";
322 _pass(context) = false;
323 }
324 }
325};
326
Václav Kubernát6797df02019-03-18 20:21:50 +0100327struct create_class {
Václav Kubernátb61336d2018-05-28 17:35:03 +0200328 template <typename Iterator, typename Exception, typename Context>
Václav Kubernát41378452018-06-06 16:29:40 +0200329 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
Václav Kubernátb61336d2018-05-28 17:35:03 +0200330 {
331 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát41378452018-06-06 16:29:40 +0200332 if (parserContext.m_errorMsg.empty())
333 parserContext.m_errorMsg = "Couldn't parse create/delete command.";
334 return x3::error_handler_result::rethrow;
Václav Kubernátb61336d2018-05-28 17:35:03 +0200335 }
336};
337
Václav Kubernát6797df02019-03-18 20:21:50 +0100338struct delete_class {
339 template <typename Iterator, typename Exception, typename Context>
340 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
341 {
342 auto& parserContext = x3::get<parser_context_tag>(context);
343 if (parserContext.m_errorMsg.empty())
344 parserContext.m_errorMsg = "Couldn't parse create/delete command.";
345 return x3::error_handler_result::rethrow;
346 }
Václav Kubernátb61336d2018-05-28 17:35:03 +0200347};
348
Václav Kubernát0b0272f2018-06-13 14:13:08 +0200349struct leaf_path_class {
350 template <typename T, typename Iterator, typename Context>
351 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
352 {
353 auto& parserContext = x3::get<parser_context_tag>(context);
354 try {
Václav Kubernát744f57f2018-06-29 22:46:26 +0200355 auto leaf = boost::get<leaf_>(ast.m_nodes.back().m_suffix);
Václav Kubernát0b0272f2018-06-13 14:13:08 +0200356 } catch (boost::bad_get&) {
357 parserContext.m_errorMsg = "This is not a path to leaf.";
358 _pass(context) = false;
359 }
360 }
361};
362
Václav Kubernáteeb38842019-03-20 19:46:05 +0100363// This handler only checks if the module exists
364// It doesn't set any ParserContext flags (except the error message)
365struct data_module_prefix_class {
366 template <typename T, typename Iterator, typename Context>
367 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
368 {
369 auto& parserContext = x3::get<parser_context_tag>(context);
370 const auto& schema = parserContext.m_schema;
371
372 if (!schema.isModule(parserContext.m_curPath, ast.m_name)) {
373 parserContext.m_errorMsg = "Invalid module name.";
374 _pass(context) = false;
375 }
376 }
377};
378
Václav Kubernátebca2552018-06-08 19:06:02 +0200379struct leaf_data_class {
Václav Kubernát0b0272f2018-06-13 14:13:08 +0200380 template <typename Iterator, typename Exception, typename Context>
381 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
382 {
383 auto& parserContext = x3::get<parser_context_tag>(context);
384 auto& schema = parserContext.m_schema;
385 if (parserContext.m_errorMsg.empty()) {
Václav Kubernát744f57f2018-06-29 22:46:26 +0200386 leaf_ leaf = boost::get<leaf_>(parserContext.m_curPath.m_nodes.back().m_suffix);
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200387 schemaPath_ location = pathWithoutLastNode(parserContext.m_curPath);
Václav Kubernáteeb38842019-03-20 19:46:05 +0100388 boost::optional<std::string> module;
389 if (parserContext.m_curPath.m_nodes.back().m_prefix)
390 module = parserContext.m_curPath.m_nodes.back().m_prefix.value().m_name;
391 parserContext.m_errorMsg = "Expected " + leafDataTypeToString(schema.leafType(location, {module, leaf.m_name})) + " here:";
Václav Kubernát0b0272f2018-06-13 14:13:08 +0200392 return x3::error_handler_result::fail;
393 }
394 return x3::error_handler_result::rethrow;
395 }
Václav Kubernátebca2552018-06-08 19:06:02 +0200396};
397
398struct leaf_data_base_class {
399 yang::LeafDataTypes m_type;
400
401 leaf_data_base_class(yang::LeafDataTypes type)
402 : m_type(type)
403 {
404 }
405
406 template <typename T, typename Iterator, typename Context>
407 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
408 {
409 auto& parserContext = x3::get<parser_context_tag>(context);
410 auto& schema = parserContext.m_schema;
Václav Kubernát744f57f2018-06-29 22:46:26 +0200411 boost::optional<std::string> module;
412 if (parserContext.m_curPath.m_nodes.back().m_prefix)
413 module = parserContext.m_curPath.m_nodes.back().m_prefix.value().m_name;
Václav Kubernátebca2552018-06-08 19:06:02 +0200414
Václav Kubernát744f57f2018-06-29 22:46:26 +0200415 leaf_ leaf = boost::get<leaf_>(parserContext.m_curPath.m_nodes.back().m_suffix);
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200416 schemaPath_ location = pathWithoutLastNode(parserContext.m_curPath);
Václav Kubernátebca2552018-06-08 19:06:02 +0200417
Václav Kubernát744f57f2018-06-29 22:46:26 +0200418 if (schema.leafType(location, {module, leaf.m_name}) != m_type) {
Václav Kubernátebca2552018-06-08 19:06:02 +0200419 _pass(context) = false;
420 }
421 }
422};
423
424struct leaf_data_enum_class : leaf_data_base_class {
425 leaf_data_enum_class()
426 : leaf_data_base_class(yang::LeafDataTypes::Enum)
427 {
428 }
429
430 template <typename T, typename Iterator, typename Context>
431 void on_success(Iterator const& start, Iterator const& end, T& ast, Context const& context)
432 {
433 leaf_data_base_class::on_success(start, end, ast, context);
Václav Kubernáteeb38842019-03-20 19:46:05 +0100434 // Base class on_success cannot return for us, so we check if it failed the parser.
435 if (_pass(context) == false)
436 return;
Václav Kubernátebca2552018-06-08 19:06:02 +0200437 auto& parserContext = x3::get<parser_context_tag>(context);
438 auto& schema = parserContext.m_schema;
Václav Kubernát744f57f2018-06-29 22:46:26 +0200439 boost::optional<std::string> module;
440 if (parserContext.m_curPath.m_nodes.back().m_prefix)
441 module = parserContext.m_curPath.m_nodes.back().m_prefix.value().m_name;
Václav Kubernátebca2552018-06-08 19:06:02 +0200442
Václav Kubernát744f57f2018-06-29 22:46:26 +0200443 leaf_ leaf = boost::get<leaf_>(parserContext.m_curPath.m_nodes.back().m_suffix);
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200444 schemaPath_ location = pathWithoutLastNode(parserContext.m_curPath);
Václav Kubernátebca2552018-06-08 19:06:02 +0200445
Václav Kubernát744f57f2018-06-29 22:46:26 +0200446 if (!schema.leafEnumHasValue(location, {module, leaf.m_name}, ast.m_value)) {
Václav Kubernátebca2552018-06-08 19:06:02 +0200447 _pass(context) = false;
448 }
449 }
450};
451
452struct leaf_data_decimal_class : leaf_data_base_class {
453 leaf_data_decimal_class()
454 : leaf_data_base_class(yang::LeafDataTypes::Decimal)
455 {
456 }
457};
458
459struct leaf_data_bool_class : leaf_data_base_class {
460 leaf_data_bool_class()
461 : leaf_data_base_class(yang::LeafDataTypes::Bool)
462 {
463 }
464};
465
466struct leaf_data_int_class : leaf_data_base_class {
467 leaf_data_int_class()
468 : leaf_data_base_class(yang::LeafDataTypes::Int)
469 {
470 }
471};
472
473struct leaf_data_uint_class : leaf_data_base_class {
474 leaf_data_uint_class()
475 : leaf_data_base_class(yang::LeafDataTypes::Uint)
476 {
477 }
478};
479
480struct leaf_data_string_class : leaf_data_base_class {
481 leaf_data_string_class()
482 : leaf_data_base_class(yang::LeafDataTypes::String)
483 {
484 }
485};
486
Václav Kubernátab538992019-03-06 15:30:50 +0100487struct leaf_data_binary_data_class;
488
489struct leaf_data_binary_class : leaf_data_base_class {
490 leaf_data_binary_class()
491 : leaf_data_base_class(yang::LeafDataTypes::Binary)
492 {
493 }
494};
495
Václav Kubernáteeb38842019-03-20 19:46:05 +0100496struct leaf_data_identityRef_data_class;
497
498struct leaf_data_identityRef_class : leaf_data_base_class {
499 leaf_data_identityRef_class()
500 : leaf_data_base_class(yang::LeafDataTypes::IdentityRef)
501 {
502 }
503
504 template <typename T, typename Iterator, typename Context>
505 void on_success(Iterator const& start, Iterator const& end, T& ast, Context const& context)
506 {
507 // FIXME: can I reuse leaf_data_enum_class somehow..?
508 leaf_data_base_class::on_success(start, end, ast, context);
509 // Base class on_success cannot return for us, so we check if it failed the parser.
510 if (_pass(context) == false)
511 return;
512 auto& parserContext = x3::get<parser_context_tag>(context);
513 auto& schema = parserContext.m_schema;
514 boost::optional<std::string> module;
515 if (parserContext.m_curPath.m_nodes.back().m_prefix)
516 module = parserContext.m_curPath.m_nodes.back().m_prefix.value().m_name;
517
518 leaf_ leaf = boost::get<leaf_>(parserContext.m_curPath.m_nodes.back().m_suffix);
519 schemaPath_ location = pathWithoutLastNode(parserContext.m_curPath);
520
521 ModuleValuePair pair;
522 if (ast.m_prefix) {
523 pair.first = ast.m_prefix.get().m_name;
524 }
525 pair.second = ast.m_value;
526
527 if (!schema.leafIdentityIsValid(location, {module, leaf.m_name}, pair)) {
528 _pass(context) = false;
529 }
530 }
531};
532
Václav Kubernát07204242018-06-04 18:12:09 +0200533struct set_class {
Václav Kubernát07204242018-06-04 18:12:09 +0200534 template <typename Iterator, typename Exception, typename Context>
535 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const& x, Context const& context)
536 {
537 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát41378452018-06-06 16:29:40 +0200538 if (parserContext.m_errorMsg.empty())
539 parserContext.m_errorMsg = "Expected " + x.which() + " here:";
540 return x3::error_handler_result::rethrow;
Václav Kubernát07204242018-06-04 18:12:09 +0200541 }
542};
543
Václav Kubernát812ee282018-08-30 17:10:03 +0200544struct commit_class;
545
Václav Kubernát054cc992019-02-21 14:23:52 +0100546struct help_class;
547
Václav Kubernátb6ff0b62018-08-30 16:14:53 +0200548struct get_class;
549
Václav Kubernátb61336d2018-05-28 17:35:03 +0200550struct command_class {
551 template <typename Iterator, typename Exception, typename Context>
552 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const& x, Context const& context)
553 {
554 auto& parserContext = x3::get<parser_context_tag>(context);
555 auto& error_handler = x3::get<x3::error_handler_tag>(context).get();
Václav Kubernát41378452018-06-06 16:29:40 +0200556 if (parserContext.m_errorMsg.empty()) {
557 parserContext.m_errorMsg = "Unknown command.";
558 }
559 error_handler(x.where(), parserContext.m_errorMsg);
Václav Kubernátb61336d2018-05-28 17:35:03 +0200560 return x3::error_handler_result::fail;
561 }
562};
Václav Kubernát5c75b252018-10-10 18:33:47 +0200563
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100564struct initializePath_class {
Václav Kubernát5c75b252018-10-10 18:33:47 +0200565 template <typename T, typename Iterator, typename Context>
566 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
567 {
568 auto& parserContext = x3::get<parser_context_tag>(context);
569 parserContext.m_curPath = parserContext.m_curPathOrig;
570 parserContext.m_tmpListKeys.clear();
571 parserContext.m_tmpListName.clear();
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100572 parserContext.m_suggestions.clear();
Václav Kubernát5c75b252018-10-10 18:33:47 +0200573 if (!parserContext.m_curPath.m_nodes.empty() && parserContext.m_curPath.m_nodes.at(0).m_prefix)
574 parserContext.m_topLevelModulePresent = true;
575 else
576 parserContext.m_topLevelModulePresent = false;
577 }
578};
Václav Kubernátd6fd2492018-11-19 15:11:16 +0100579
580struct trailingSlash_class;
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100581
582struct createPathSuggestions_class {
583 template <typename T, typename Iterator, typename Context>
584 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
585 {
586 auto& parserContext = x3::get<parser_context_tag>(context);
587 const auto& schema = parserContext.m_schema;
588
589 parserContext.m_completionIterator = begin;
590 parserContext.m_suggestions = schema.childNodes(parserContext.m_curPath, Recursion::NonRecursive);
591 }
592};
Václav Kubernát329c6c32019-02-06 16:41:53 +0100593
594std::set<std::string> generateMissingKeyCompletionSet(std::set<std::string> keysNeeded, std::set<std::string> currentSet);
595
596struct createKeySuggestions_class {
597 template <typename T, typename Iterator, typename Context>
598 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
599 {
600 auto& parserContext = x3::get<parser_context_tag>(context);
601 const auto& schema = parserContext.m_schema;
602
603 parserContext.m_completionIterator = begin;
604
605 const auto& keysNeeded = schema.listKeys(parserContext.m_curPath, {parserContext.m_curModule, parserContext.m_tmpListName});
606 parserContext.m_suggestions = generateMissingKeyCompletionSet(keysNeeded, parserContext.m_tmpListKeys);
607 }
608};
609
610struct suggestKeysEnd_class {
611 template <typename T, typename Iterator, typename Context>
612 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
613 {
614 auto& parserContext = x3::get<parser_context_tag>(context);
615 const auto& schema = parserContext.m_schema;
616
617 parserContext.m_completionIterator = begin;
618 const auto& keysNeeded = schema.listKeys(parserContext.m_curPath, {parserContext.m_curModule, parserContext.m_tmpListName});
619 if (generateMissingKeyCompletionSet(keysNeeded, parserContext.m_tmpListKeys).empty()) {
620 parserContext.m_suggestions = {"]/"};
621 } else {
622 parserContext.m_suggestions = {"]"};
623 }
624 }
625};
Václav Kubernát57272422019-02-08 12:48:24 +0100626
627struct commandNamesVisitor {
628 template <typename T>
629 auto operator()(boost::type<T>)
630 {
631 return T::name;
632 }
633};
634
635struct createCommandSuggestions_class {
636 template <typename T, typename Iterator, typename Context>
637 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
638 {
639 auto& parserContext = x3::get<parser_context_tag>(context);
640 parserContext.m_completionIterator = begin;
641
642 parserContext.m_suggestions.clear();
643 boost::mpl::for_each<CommandTypes, boost::type<boost::mpl::_>>([&parserContext](auto cmd) {
644 parserContext.m_suggestions.emplace(commandNamesVisitor()(cmd));
645 });
646 }
647};
Václav Kubernátac035d62019-02-18 10:59:08 +0100648
649struct completing_class {
650 template <typename T, typename Iterator, typename Context>
651 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
652 {
653 auto& parserContext = x3::get<parser_context_tag>(context);
654
655 if (!parserContext.m_completing)
656 _pass(context) = false;
657 }
658};
Václav Kubernát989b5de2019-02-20 16:28:35 +0100659
660struct createEnumSuggestions_class {
661 template <typename T, typename Iterator, typename Context>
662 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
663 {
664 auto& parserContext = x3::get<parser_context_tag>(context);
665 parserContext.m_completionIterator = begin;
666 const Schema& schema = parserContext.m_schema;
667
668 boost::optional<std::string> module;
669 if (parserContext.m_curPath.m_nodes.back().m_prefix)
670 module = parserContext.m_curPath.m_nodes.back().m_prefix.value().m_name;
671
672 leaf_ leaf = boost::get<leaf_>(parserContext.m_curPath.m_nodes.back().m_suffix);
673 schemaPath_ location = pathWithoutLastNode(parserContext.m_curPath);
674
Václav Kubernáteeb38842019-03-20 19:46:05 +0100675 // Only generate completions if the type is enum so that we don't
676 // overwrite some other completions.
677 if (schema.leafType(location, {module, leaf.m_name}) == yang::LeafDataTypes::Enum)
678 parserContext.m_suggestions = schema.enumValues(location, {module, leaf.m_name});
679 }
680};
681
682// FIXME: can I reuse createEnumSuggestions?
683struct createIdentitySuggestions_class {
684 template <typename T, typename Iterator, typename Context>
685 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
686 {
687 auto& parserContext = x3::get<parser_context_tag>(context);
688 parserContext.m_completionIterator = begin;
689 const Schema& schema = parserContext.m_schema;
690
691 boost::optional<std::string> module;
692 if (parserContext.m_curPath.m_nodes.back().m_prefix)
693 module = parserContext.m_curPath.m_nodes.back().m_prefix.value().m_name;
694
695 leaf_ leaf = boost::get<leaf_>(parserContext.m_curPath.m_nodes.back().m_suffix);
696 schemaPath_ location = pathWithoutLastNode(parserContext.m_curPath);
697
698 // Only generate completions if the type is identityref so that we
699 // don't overwrite some other completions.
700 if (schema.leafType(location, {module, leaf.m_name}) == yang::LeafDataTypes::IdentityRef)
701 parserContext.m_suggestions = schema.validIdentities(location, {module, leaf.m_name}, Prefixes::WhenNeeded);
Václav Kubernát989b5de2019-02-20 16:28:35 +0100702 }
703};