blob: 2e4753d206d4d4691692131606f5fc8e34b0b483 [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>
Václav Kubernát509ce652019-05-29 19:46:44 +020012#include <boost/spirit/home/x3.hpp>
13#include <boost/spirit/home/x3/support/utility/error_reporting.hpp>
14
15
Václav Kubernát57272422019-02-08 12:48:24 +010016#include "ast_commands.hpp"
Václav Kubernát48fc3832018-05-28 14:21:22 +020017#include "schema.hpp"
Václav Kubernátebca2552018-06-08 19:06:02 +020018#include "utils.hpp"
Václav Kubernát329c6c32019-02-06 16:41:53 +010019namespace x3 = boost::spirit::x3;
20
21struct parser_context_tag;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020022
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020023struct keyValue_class {
24 template <typename T, typename Iterator, typename Context>
25 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
26 {
27 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát48fc3832018-05-28 14:21:22 +020028 const Schema& schema = parserContext.m_schema;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020029
30 if (parserContext.m_tmpListKeys.find(ast.first) != parserContext.m_tmpListKeys.end()) {
31 _pass(context) = false;
32 parserContext.m_errorMsg = "Key \"" + ast.first + "\" was entered more than once.";
Václav Kubernát744f57f2018-06-29 22:46:26 +020033 } else if (!schema.listHasKey(parserContext.m_curPath, {parserContext.m_curModule, parserContext.m_tmpListName}, ast.first)) {
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020034 _pass(context) = false;
35 parserContext.m_errorMsg = parserContext.m_tmpListName + " is not indexed by \"" + ast.first + "\".";
Václav Kubernát41378452018-06-06 16:29:40 +020036 } else {
37 parserContext.m_tmpListKeys.insert(ast.first);
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020038 }
39 }
Václav Kubernát41378452018-06-06 16:29:40 +020040
41 template <typename Iterator, typename Exception, typename Context>
42 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
43 {
44 auto& parserContext = x3::get<parser_context_tag>(context);
45 parserContext.m_errorMsg = "Error parsing key values here:";
46 return x3::error_handler_result::rethrow;
47 }
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020048};
Václav Kubernát41378452018-06-06 16:29:40 +020049
Václav Kubernát744f57f2018-06-29 22:46:26 +020050struct node_identifier_class {
51 template <typename T, typename Iterator, typename Context>
52 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
53 {
54 auto& parserContext = x3::get<parser_context_tag>(context);
55
56 if (!parserContext.m_topLevelModulePresent) {
57 if (parserContext.m_errorMsg.empty())
58 parserContext.m_errorMsg = "You have to specify a top level module.";
59 _pass(context) = false;
60 }
61 }
62};
63
Václav Kubernát89728d82018-09-13 16:28:28 +020064struct key_identifier_class;
65
Václav Kubernát744f57f2018-06-29 22:46:26 +020066struct module_identifier_class;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020067
68struct listPrefix_class {
69 template <typename T, typename Iterator, typename Context>
70 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
71 {
72 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát48fc3832018-05-28 14:21:22 +020073 const Schema& schema = parserContext.m_schema;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020074
Václav Kubernát744f57f2018-06-29 22:46:26 +020075 if (schema.isList(parserContext.m_curPath, {parserContext.m_curModule, ast})) {
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020076 parserContext.m_tmpListName = ast;
77 } else {
78 _pass(context) = false;
79 }
80 }
81};
82
83struct listSuffix_class {
84 template <typename T, typename Iterator, typename Context>
85 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
86 {
87 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát48fc3832018-05-28 14:21:22 +020088 const Schema& schema = parserContext.m_schema;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020089
Václav Kubernát744f57f2018-06-29 22:46:26 +020090 const auto& keysNeeded = schema.listKeys(parserContext.m_curPath, {parserContext.m_curModule, parserContext.m_tmpListName});
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020091 std::set<std::string> keysSupplied;
92 for (const auto& it : ast)
93 keysSupplied.insert(it.first);
94
95 if (keysNeeded != keysSupplied) {
96 parserContext.m_errorMsg = "Not enough keys for " + parserContext.m_tmpListName + ". " +
97 "These keys were not supplied:";
98 std::set<std::string> missingKeys;
99 std::set_difference(keysNeeded.begin(), keysNeeded.end(),
100 keysSupplied.begin(), keysSupplied.end(),
101 std::inserter(missingKeys, missingKeys.end()));
102
103 for (const auto& it : missingKeys)
104 parserContext.m_errorMsg += " " + it;
105 parserContext.m_errorMsg += ".";
106
107 _pass(context) = false;
108 }
109 }
Václav Kubernát41378452018-06-06 16:29:40 +0200110
111 template <typename Iterator, typename Exception, typename Context>
112 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
113 {
114 auto& parserContext = x3::get<parser_context_tag>(context);
115 if (parserContext.m_errorMsg.empty())
116 parserContext.m_errorMsg = "Expecting ']' here:";
117 return x3::error_handler_result::rethrow;
Václav Kubernát41378452018-06-06 16:29:40 +0200118 }
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200119};
120struct listElement_class {
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200121 template <typename Iterator, typename Exception, typename Context>
Václav Kubernát41378452018-06-06 16:29:40 +0200122 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200123 {
124 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát41378452018-06-06 16:29:40 +0200125 if (parserContext.m_errorMsg.empty()) {
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200126 return x3::error_handler_result::fail;
Václav Kubernát41378452018-06-06 16:29:40 +0200127 } else {
128 return x3::error_handler_result::rethrow;
129 }
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200130 }
131};
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200132struct list_class {
133 template <typename T, typename Iterator, typename Context>
134 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
135 {
136 auto& parserContext = x3::get<parser_context_tag>(context);
137 const Schema& schema = parserContext.m_schema;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200138
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200139 if (!schema.isList(parserContext.m_curPath, {parserContext.m_curModule, ast.m_name})) {
140 _pass(context) = false;
141 }
142 }
143};
Václav Kubernát60d6f292018-05-25 09:45:32 +0200144struct nodeup_class {
145 template <typename T, typename Iterator, typename Context>
146 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
147 {
148 auto& parserContext = x3::get<parser_context_tag>(context);
149
Václav Kubernát744f57f2018-06-29 22:46:26 +0200150 if (parserContext.m_curPath.m_nodes.empty())
Václav Kubernát60d6f292018-05-25 09:45:32 +0200151 _pass(context) = false;
Václav Kubernát60d6f292018-05-25 09:45:32 +0200152 }
153};
154
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200155struct container_class {
156 template <typename T, typename Iterator, typename Context>
157 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
158 {
159 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát48fc3832018-05-28 14:21:22 +0200160 const auto& schema = parserContext.m_schema;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200161
Václav Kubernát744f57f2018-06-29 22:46:26 +0200162 if (!schema.isContainer(parserContext.m_curPath, {parserContext.m_curModule, ast.m_name}))
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200163 _pass(context) = false;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200164 }
165};
166
Václav Kubernát07204242018-06-04 18:12:09 +0200167struct leaf_class {
168 template <typename T, typename Iterator, typename Context>
169 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
170 {
171 auto& parserContext = x3::get<parser_context_tag>(context);
172 const auto& schema = parserContext.m_schema;
173
Václav Kubernát744f57f2018-06-29 22:46:26 +0200174 if (!schema.isLeaf(parserContext.m_curPath, {parserContext.m_curModule, ast.m_name}))
175 _pass(context) = false;
176 }
177};
178
Václav Kubernát744f57f2018-06-29 22:46:26 +0200179struct module_class {
180 template <typename T, typename Iterator, typename Context>
181 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
182 {
183 auto& parserContext = x3::get<parser_context_tag>(context);
184 const auto& schema = parserContext.m_schema;
185
Václav Kubernát75877de2019-11-20 17:43:02 +0100186 if (schema.isModule(ast.m_name)) {
Václav Kubernát744f57f2018-06-29 22:46:26 +0200187 parserContext.m_curModule = ast.m_name;
188 parserContext.m_topLevelModulePresent = true;
Václav Kubernát07204242018-06-04 18:12:09 +0200189 } else {
Václav Kubernát744f57f2018-06-29 22:46:26 +0200190 parserContext.m_errorMsg = "Invalid module name.";
Václav Kubernát07204242018-06-04 18:12:09 +0200191 _pass(context) = false;
192 }
193 }
194};
195
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200196struct schemaNode_class {
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200197 template <typename T, typename Iterator, typename Context>
Václav Kubernát744f57f2018-06-29 22:46:26 +0200198 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200199 {
Václav Kubernát744f57f2018-06-29 22:46:26 +0200200 auto& parserContext = x3::get<parser_context_tag>(context);
201 if (ast.m_suffix.type() == typeid(nodeup_)) {
202 parserContext.m_curPath.m_nodes.pop_back();
203 if (parserContext.m_curPath.m_nodes.empty())
204 parserContext.m_topLevelModulePresent = false;
205 } else {
206 parserContext.m_curPath.m_nodes.push_back(ast);
207 parserContext.m_curModule = boost::none;
208 }
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200209 }
Václav Kubernát744f57f2018-06-29 22:46:26 +0200210};
Václav Kubernát07204242018-06-04 18:12:09 +0200211
Václav Kubernát39ae9592019-02-05 17:35:16 +0100212struct dataNodeList_class {
213 template <typename T, typename Iterator, typename Context>
214 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
215 {
216 auto& parserContext = x3::get<parser_context_tag>(context);
217 parserContext.m_curPath.m_nodes.push_back(dataNodeToSchemaNode(ast));
218 }
219};
Václav Kubernát5c75b252018-10-10 18:33:47 +0200220
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200221struct dataNode_class {
222 template <typename T, typename Iterator, typename Context>
223 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
224 {
225 auto& parserContext = x3::get<parser_context_tag>(context);
226 if (ast.m_suffix.type() == typeid(nodeup_)) {
227 parserContext.m_curPath.m_nodes.pop_back();
228 if (parserContext.m_curPath.m_nodes.empty())
229 parserContext.m_topLevelModulePresent = false;
230 } else {
231 parserContext.m_curPath.m_nodes.push_back(dataNodeToSchemaNode(ast));
232 parserContext.m_curModule = boost::none;
233 }
234 }
235};
236
Václav Kubernát37171a12018-08-31 17:01:48 +0200237struct absoluteStart_class {
238 template <typename T, typename Iterator, typename Context>
239 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
240 {
241 auto& parserContext = x3::get<parser_context_tag>(context);
242 parserContext.m_curPath.m_nodes.clear();
Václav Kubernátb9621052019-03-18 18:27:49 +0100243 parserContext.m_topLevelModulePresent = false;
Václav Kubernát37171a12018-08-31 17:01:48 +0200244 }
245};
246
Václav Kubernát5c75b252018-10-10 18:33:47 +0200247struct dataNodesListEnd_class;
248
249struct dataPathListEnd_class;
250
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200251struct dataPath_class {
252 template <typename Iterator, typename Exception, typename Context>
253 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
254 {
255 auto& parserContext = x3::get<parser_context_tag>(context);
256 if (parserContext.m_errorMsg.empty()) {
257 parserContext.m_errorMsg = "Expected path.";
258 return x3::error_handler_result::fail;
259 } else {
260 return x3::error_handler_result::rethrow;
261 }
262 }
263};
264
265struct schemaPath_class {
Václav Kubernát07204242018-06-04 18:12:09 +0200266 template <typename Iterator, typename Exception, typename Context>
Václav Kubernát41378452018-06-06 16:29:40 +0200267 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
Václav Kubernát07204242018-06-04 18:12:09 +0200268 {
269 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát41378452018-06-06 16:29:40 +0200270 if (parserContext.m_errorMsg.empty()) {
271 parserContext.m_errorMsg = "Expected path.";
Václav Kubernát07204242018-06-04 18:12:09 +0200272 return x3::error_handler_result::fail;
Václav Kubernát41378452018-06-06 16:29:40 +0200273 } else {
274 return x3::error_handler_result::rethrow;
275 }
Václav Kubernát07204242018-06-04 18:12:09 +0200276 }
277};
278
Václav Kubernát6d791432018-10-25 16:00:35 +0200279struct discard_class;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200280
Václav Kubernát11afac72018-07-18 14:59:53 +0200281struct ls_class;
282
Václav Kubernát744f57f2018-06-29 22:46:26 +0200283struct cd_class {
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200284 template <typename Iterator, typename Exception, typename Context>
285 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const& x, Context const& context)
286 {
287 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát41378452018-06-06 16:29:40 +0200288 if (parserContext.m_errorMsg.empty())
289 parserContext.m_errorMsg = "Expected " + x.which() + " here:";
290 return x3::error_handler_result::rethrow;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200291 }
292};
Václav Kubernátb61336d2018-05-28 17:35:03 +0200293
Václav Kubernát6797df02019-03-18 20:21:50 +0100294struct presenceContainerPath_class {
Václav Kubernátb61336d2018-05-28 17:35:03 +0200295 template <typename T, typename Iterator, typename Context>
296 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
297 {
298 auto& parserContext = x3::get<parser_context_tag>(context);
299 const auto& schema = parserContext.m_schema;
300 try {
Václav Kubernát744f57f2018-06-29 22:46:26 +0200301 boost::optional<std::string> module;
Václav Kubernát6797df02019-03-18 20:21:50 +0100302 if (ast.m_nodes.back().m_prefix)
303 module = ast.m_nodes.back().m_prefix.value().m_name;
304 container_ cont = boost::get<container_>(ast.m_nodes.back().m_suffix);
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200305 schemaPath_ location = pathWithoutLastNode(parserContext.m_curPath);
Václav Kubernátb61336d2018-05-28 17:35:03 +0200306
Václav Kubernát744f57f2018-06-29 22:46:26 +0200307 if (!schema.isPresenceContainer(location, {module, cont.m_name})) {
Václav Kubernát41378452018-06-06 16:29:40 +0200308 parserContext.m_errorMsg = "This container is not a presence container.";
Václav Kubernátb61336d2018-05-28 17:35:03 +0200309 _pass(context) = false;
Václav Kubernátb61336d2018-05-28 17:35:03 +0200310 }
311 } catch (boost::bad_get&) {
Václav Kubernát41378452018-06-06 16:29:40 +0200312 parserContext.m_errorMsg = "This is not a container.";
Václav Kubernátb61336d2018-05-28 17:35:03 +0200313 _pass(context) = false;
Václav Kubernátb61336d2018-05-28 17:35:03 +0200314 }
315 }
Václav Kubernát6797df02019-03-18 20:21:50 +0100316};
Václav Kubernátb61336d2018-05-28 17:35:03 +0200317
Václav Kubernátf5f64f02019-03-19 17:15:47 +0100318struct listInstancePath_class {
319 template <typename T, typename Iterator, typename Context>
320 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
321 {
322 auto& parserContext = x3::get<parser_context_tag>(context);
323 if (ast.m_nodes.back().m_suffix.type() != typeid(listElement_)) {
324 parserContext.m_errorMsg = "This is not a list instance.";
325 _pass(context) = false;
326 }
327 }
328};
329
Václav Kubernát8028f942019-09-25 16:03:23 +0200330struct space_separator_class {
331 template <typename T, typename Iterator, typename Context>
332 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
333 {
334 auto& parserContext = x3::get<parser_context_tag>(context);
335 parserContext.m_suggestions.clear();
Václav Kubernáte69133a2019-11-01 19:01:34 +0100336 parserContext.m_completionSuffix.clear();
Václav Kubernát8028f942019-09-25 16:03:23 +0200337 }
338};
339
Václav Kubernát6797df02019-03-18 20:21:50 +0100340struct create_class {
Václav Kubernátb61336d2018-05-28 17:35:03 +0200341 template <typename Iterator, typename Exception, typename Context>
Václav Kubernát41378452018-06-06 16:29:40 +0200342 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
Václav Kubernátb61336d2018-05-28 17:35:03 +0200343 {
344 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát41378452018-06-06 16:29:40 +0200345 if (parserContext.m_errorMsg.empty())
346 parserContext.m_errorMsg = "Couldn't parse create/delete command.";
347 return x3::error_handler_result::rethrow;
Václav Kubernátb61336d2018-05-28 17:35:03 +0200348 }
349};
350
Václav Kubernát6797df02019-03-18 20:21:50 +0100351struct delete_class {
352 template <typename Iterator, typename Exception, typename Context>
353 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
354 {
355 auto& parserContext = x3::get<parser_context_tag>(context);
356 if (parserContext.m_errorMsg.empty())
357 parserContext.m_errorMsg = "Couldn't parse create/delete command.";
358 return x3::error_handler_result::rethrow;
359 }
Václav Kubernátb61336d2018-05-28 17:35:03 +0200360};
361
Václav Kubernát0b0272f2018-06-13 14:13:08 +0200362struct leaf_path_class {
363 template <typename T, typename Iterator, typename Context>
364 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
365 {
366 auto& parserContext = x3::get<parser_context_tag>(context);
367 try {
Václav Kubernát744f57f2018-06-29 22:46:26 +0200368 auto leaf = boost::get<leaf_>(ast.m_nodes.back().m_suffix);
Václav Kubernát0b0272f2018-06-13 14:13:08 +0200369 } catch (boost::bad_get&) {
370 parserContext.m_errorMsg = "This is not a path to leaf.";
371 _pass(context) = false;
372 }
373 }
374};
375
Václav Kubernáteeb38842019-03-20 19:46:05 +0100376// This handler only checks if the module exists
377// It doesn't set any ParserContext flags (except the error message)
378struct data_module_prefix_class {
379 template <typename T, typename Iterator, typename Context>
380 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
381 {
382 auto& parserContext = x3::get<parser_context_tag>(context);
383 const auto& schema = parserContext.m_schema;
384
385 if (!schema.isModule(parserContext.m_curPath, ast.m_name)) {
386 parserContext.m_errorMsg = "Invalid module name.";
387 _pass(context) = false;
388 }
389 }
390};
391
Václav Kubernátebca2552018-06-08 19:06:02 +0200392struct leaf_data_class {
Václav Kubernát0b0272f2018-06-13 14:13:08 +0200393 template <typename Iterator, typename Exception, typename Context>
394 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
395 {
396 auto& parserContext = x3::get<parser_context_tag>(context);
397 auto& schema = parserContext.m_schema;
398 if (parserContext.m_errorMsg.empty()) {
Václav Kubernát744f57f2018-06-29 22:46:26 +0200399 leaf_ leaf = boost::get<leaf_>(parserContext.m_curPath.m_nodes.back().m_suffix);
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200400 schemaPath_ location = pathWithoutLastNode(parserContext.m_curPath);
Václav Kubernáteeb38842019-03-20 19:46:05 +0100401 boost::optional<std::string> module;
402 if (parserContext.m_curPath.m_nodes.back().m_prefix)
403 module = parserContext.m_curPath.m_nodes.back().m_prefix.value().m_name;
404 parserContext.m_errorMsg = "Expected " + leafDataTypeToString(schema.leafType(location, {module, leaf.m_name})) + " here:";
Václav Kubernát0b0272f2018-06-13 14:13:08 +0200405 return x3::error_handler_result::fail;
406 }
407 return x3::error_handler_result::rethrow;
408 }
Václav Kubernátebca2552018-06-08 19:06:02 +0200409};
410
Václav Kubernát90de9502019-11-20 17:19:44 +0100411template <yang::LeafDataTypes TYPE>
Václav Kubernátebca2552018-06-08 19:06:02 +0200412struct leaf_data_base_class {
413 yang::LeafDataTypes m_type;
414
Ivona Oboňová88c78ca2019-07-02 18:40:07 +0200415 leaf_data_base_class()
416 : m_type(TYPE)
Václav Kubernátebca2552018-06-08 19:06:02 +0200417 {
418 }
419
420 template <typename T, typename Iterator, typename Context>
421 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
422 {
423 auto& parserContext = x3::get<parser_context_tag>(context);
424 auto& schema = parserContext.m_schema;
Václav Kubernát744f57f2018-06-29 22:46:26 +0200425 boost::optional<std::string> module;
426 if (parserContext.m_curPath.m_nodes.back().m_prefix)
427 module = parserContext.m_curPath.m_nodes.back().m_prefix.value().m_name;
Václav Kubernátebca2552018-06-08 19:06:02 +0200428
Václav Kubernát744f57f2018-06-29 22:46:26 +0200429 leaf_ leaf = boost::get<leaf_>(parserContext.m_curPath.m_nodes.back().m_suffix);
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200430 schemaPath_ location = pathWithoutLastNode(parserContext.m_curPath);
Václav Kubernátebca2552018-06-08 19:06:02 +0200431
Václav Kubernát6a8d1d92019-04-24 20:30:36 +0200432 auto type = schema.leafType(location, {module, leaf.m_name});
433 if (type == yang::LeafDataTypes::LeafRef) {
434 type = schema.leafrefBase(location, {module, leaf.m_name});
435 }
436 if (type != m_type) {
Václav Kubernátebca2552018-06-08 19:06:02 +0200437 _pass(context) = false;
438 }
439 }
440};
441
Ivona Oboňová88c78ca2019-07-02 18:40:07 +0200442struct leaf_data_binary_data_class;
443
444struct leaf_data_enum_class : leaf_data_base_class<yang::LeafDataTypes::Enum> {
445 using leaf_data_base_class::leaf_data_base_class;
Václav Kubernátebca2552018-06-08 19:06:02 +0200446
447 template <typename T, typename Iterator, typename Context>
448 void on_success(Iterator const& start, Iterator const& end, T& ast, Context const& context)
449 {
450 leaf_data_base_class::on_success(start, end, ast, context);
Václav Kubernáteeb38842019-03-20 19:46:05 +0100451 // Base class on_success cannot return for us, so we check if it failed the parser.
452 if (_pass(context) == false)
453 return;
Václav Kubernátebca2552018-06-08 19:06:02 +0200454 auto& parserContext = x3::get<parser_context_tag>(context);
455 auto& schema = parserContext.m_schema;
Václav Kubernát744f57f2018-06-29 22:46:26 +0200456 boost::optional<std::string> module;
457 if (parserContext.m_curPath.m_nodes.back().m_prefix)
458 module = parserContext.m_curPath.m_nodes.back().m_prefix.value().m_name;
Václav Kubernátebca2552018-06-08 19:06:02 +0200459
Václav Kubernát744f57f2018-06-29 22:46:26 +0200460 leaf_ leaf = boost::get<leaf_>(parserContext.m_curPath.m_nodes.back().m_suffix);
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200461 schemaPath_ location = pathWithoutLastNode(parserContext.m_curPath);
Václav Kubernátebca2552018-06-08 19:06:02 +0200462
Václav Kubernát744f57f2018-06-29 22:46:26 +0200463 if (!schema.leafEnumHasValue(location, {module, leaf.m_name}, ast.m_value)) {
Václav Kubernátebca2552018-06-08 19:06:02 +0200464 _pass(context) = false;
Václav Kubernát69710252019-11-15 17:08:30 +0100465
466 parserContext.m_errorMsg = "Expected an enum here. Allowed values:";
467 for (const auto& it : schema.enumValues(location, {module, leaf.m_name})) {
468 parserContext.m_errorMsg += " " + it;
469 }
Václav Kubernátebca2552018-06-08 19:06:02 +0200470 }
471 }
472};
473
Václav Kubernáteeb38842019-03-20 19:46:05 +0100474struct leaf_data_identityRef_data_class;
475
Ivona Oboňová88c78ca2019-07-02 18:40:07 +0200476struct leaf_data_identityRef_class : leaf_data_base_class<yang::LeafDataTypes::IdentityRef> {
477 using leaf_data_base_class::leaf_data_base_class;
Václav Kubernáteeb38842019-03-20 19:46:05 +0100478
479 template <typename T, typename Iterator, typename Context>
480 void on_success(Iterator const& start, Iterator const& end, T& ast, Context const& context)
481 {
482 // FIXME: can I reuse leaf_data_enum_class somehow..?
483 leaf_data_base_class::on_success(start, end, ast, context);
484 // Base class on_success cannot return for us, so we check if it failed the parser.
485 if (_pass(context) == false)
486 return;
487 auto& parserContext = x3::get<parser_context_tag>(context);
488 auto& schema = parserContext.m_schema;
489 boost::optional<std::string> module;
490 if (parserContext.m_curPath.m_nodes.back().m_prefix)
491 module = parserContext.m_curPath.m_nodes.back().m_prefix.value().m_name;
492
493 leaf_ leaf = boost::get<leaf_>(parserContext.m_curPath.m_nodes.back().m_suffix);
494 schemaPath_ location = pathWithoutLastNode(parserContext.m_curPath);
495
496 ModuleValuePair pair;
497 if (ast.m_prefix) {
498 pair.first = ast.m_prefix.get().m_name;
499 }
500 pair.second = ast.m_value;
501
502 if (!schema.leafIdentityIsValid(location, {module, leaf.m_name}, pair)) {
503 _pass(context) = false;
504 }
505 }
506};
507
Václav Kubernát07204242018-06-04 18:12:09 +0200508struct set_class {
Václav Kubernát07204242018-06-04 18:12:09 +0200509 template <typename Iterator, typename Exception, typename Context>
510 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const& x, Context const& context)
511 {
512 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát41378452018-06-06 16:29:40 +0200513 if (parserContext.m_errorMsg.empty())
514 parserContext.m_errorMsg = "Expected " + x.which() + " here:";
515 return x3::error_handler_result::rethrow;
Václav Kubernát07204242018-06-04 18:12:09 +0200516 }
517};
518
Václav Kubernát812ee282018-08-30 17:10:03 +0200519struct commit_class;
520
Václav Kubernát054cc992019-02-21 14:23:52 +0100521struct help_class;
522
Václav Kubernátb6ff0b62018-08-30 16:14:53 +0200523struct get_class;
524
Václav Kubernátb61336d2018-05-28 17:35:03 +0200525struct command_class {
526 template <typename Iterator, typename Exception, typename Context>
527 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const& x, Context const& context)
528 {
529 auto& parserContext = x3::get<parser_context_tag>(context);
530 auto& error_handler = x3::get<x3::error_handler_tag>(context).get();
Václav Kubernát41378452018-06-06 16:29:40 +0200531 if (parserContext.m_errorMsg.empty()) {
532 parserContext.m_errorMsg = "Unknown command.";
533 }
534 error_handler(x.where(), parserContext.m_errorMsg);
Václav Kubernátb61336d2018-05-28 17:35:03 +0200535 return x3::error_handler_result::fail;
536 }
537};
Václav Kubernát5c75b252018-10-10 18:33:47 +0200538
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100539struct initializePath_class {
Václav Kubernát5c75b252018-10-10 18:33:47 +0200540 template <typename T, typename Iterator, typename Context>
541 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
542 {
543 auto& parserContext = x3::get<parser_context_tag>(context);
544 parserContext.m_curPath = parserContext.m_curPathOrig;
545 parserContext.m_tmpListKeys.clear();
546 parserContext.m_tmpListName.clear();
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100547 parserContext.m_suggestions.clear();
Václav Kubernát5c75b252018-10-10 18:33:47 +0200548 if (!parserContext.m_curPath.m_nodes.empty() && parserContext.m_curPath.m_nodes.at(0).m_prefix)
549 parserContext.m_topLevelModulePresent = true;
550 else
551 parserContext.m_topLevelModulePresent = false;
552 }
553};
Václav Kubernátd6fd2492018-11-19 15:11:16 +0100554
555struct trailingSlash_class;
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100556
557struct createPathSuggestions_class {
558 template <typename T, typename Iterator, typename Context>
559 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
560 {
561 auto& parserContext = x3::get<parser_context_tag>(context);
562 const auto& schema = parserContext.m_schema;
563
564 parserContext.m_completionIterator = begin;
Václav Kubernáte69133a2019-11-01 19:01:34 +0100565 auto suggestions = schema.childNodes(parserContext.m_curPath, Recursion::NonRecursive);
566 std::set<std::string> suffixesAdded;
567 std::transform(suggestions.begin(), suggestions.end(),
568 std::inserter(suffixesAdded, suffixesAdded.end()),
569 [&parserContext, &schema] (auto it) {
570 ModuleNodePair node;
571 if (auto colonPos = it.find(":"); colonPos != it.npos) {
572 node.first = it.substr(0, colonPos);
573 node.second = it.substr(colonPos + 1, node.second.npos);
574 } else {
575 node.first = boost::none;
576 node.second = it;
577 }
578
579 if (schema.isLeaf(parserContext.m_curPath, node)) {
580 return it + " ";
581 }
582 if (schema.isContainer(parserContext.m_curPath, node)) {
583 return it + "/";
584 }
585 if (schema.isList(parserContext.m_curPath, node)) {
586 return it + "[";
587 }
588 return it;
589 });
590 parserContext.m_suggestions = suffixesAdded;
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100591 }
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 {
Václav Kubernát4c325482019-04-11 17:51:55 +0200622 parserContext.m_suggestions = {"]["};
Václav Kubernát329c6c32019-02-06 16:41:53 +0100623 }
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};