blob: 97c811bbf9e7067585d7aa3e616f54fa9547bd18 [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át72749c62020-01-03 16:47:34 +010033 } else if (!schema.listHasKey(parserContext.currentSchemaPath(), {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át72749c62020-01-03 16:47:34 +010075 if (schema.isList(parserContext.currentSchemaPath(), {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át72749c62020-01-03 16:47:34 +010090 const auto& keysNeeded = schema.listKeys(parserContext.currentSchemaPath(), {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át72749c62020-01-03 16:47:34 +0100139 if (!schema.isList(parserContext.currentSchemaPath(), {parserContext.m_curModule, ast.m_name})) {
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200140 _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át72749c62020-01-03 16:47:34 +0100150 if (parserContext.currentSchemaPath().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át72749c62020-01-03 16:47:34 +0100162 if (!schema.isContainer(parserContext.currentSchemaPath(), {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át72749c62020-01-03 16:47:34 +0100174 if (!schema.isLeaf(parserContext.currentSchemaPath(), {parserContext.m_curModule, ast.m_name}))
Václav Kubernát744f57f2018-06-29 22:46:26 +0200175 _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);
Václav Kubernát72749c62020-01-03 16:47:34 +0100201 parserContext.pushPathFragment(ast);
202 parserContext.m_curModule = boost::none;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200203 }
Václav Kubernát744f57f2018-06-29 22:46:26 +0200204};
Václav Kubernát07204242018-06-04 18:12:09 +0200205
Václav Kubernát39ae9592019-02-05 17:35:16 +0100206struct dataNodeList_class {
207 template <typename T, typename Iterator, typename Context>
208 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
209 {
210 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát72749c62020-01-03 16:47:34 +0100211 parserContext.pushPathFragment(ast);
Václav Kubernát39ae9592019-02-05 17:35:16 +0100212 }
213};
Václav Kubernát5c75b252018-10-10 18:33:47 +0200214
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200215struct dataNode_class {
216 template <typename T, typename Iterator, typename Context>
217 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
218 {
219 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát72749c62020-01-03 16:47:34 +0100220 parserContext.pushPathFragment(ast);
221 parserContext.m_curModule = boost::none;
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200222 }
223};
224
Václav Kubernát37171a12018-08-31 17:01:48 +0200225struct absoluteStart_class {
226 template <typename T, typename Iterator, typename Context>
227 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
228 {
229 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát72749c62020-01-03 16:47:34 +0100230 parserContext.clearPath();
Václav Kubernát37171a12018-08-31 17:01:48 +0200231 }
232};
233
Václav Kubernát5c75b252018-10-10 18:33:47 +0200234struct dataNodesListEnd_class;
235
236struct dataPathListEnd_class;
237
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200238struct dataPath_class {
239 template <typename Iterator, typename Exception, typename Context>
240 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
241 {
242 auto& parserContext = x3::get<parser_context_tag>(context);
243 if (parserContext.m_errorMsg.empty()) {
244 parserContext.m_errorMsg = "Expected path.";
245 return x3::error_handler_result::fail;
246 } else {
247 return x3::error_handler_result::rethrow;
248 }
249 }
250};
251
252struct schemaPath_class {
Václav Kubernát07204242018-06-04 18:12:09 +0200253 template <typename Iterator, typename Exception, typename Context>
Václav Kubernát41378452018-06-06 16:29:40 +0200254 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
Václav Kubernát07204242018-06-04 18:12:09 +0200255 {
256 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát41378452018-06-06 16:29:40 +0200257 if (parserContext.m_errorMsg.empty()) {
258 parserContext.m_errorMsg = "Expected path.";
Václav Kubernát07204242018-06-04 18:12:09 +0200259 return x3::error_handler_result::fail;
Václav Kubernát41378452018-06-06 16:29:40 +0200260 } else {
261 return x3::error_handler_result::rethrow;
262 }
Václav Kubernát07204242018-06-04 18:12:09 +0200263 }
264};
265
Václav Kubernát6d791432018-10-25 16:00:35 +0200266struct discard_class;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200267
Václav Kubernát11afac72018-07-18 14:59:53 +0200268struct ls_class;
269
Václav Kubernát744f57f2018-06-29 22:46:26 +0200270struct cd_class {
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200271 template <typename Iterator, typename Exception, typename Context>
272 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const& x, Context const& context)
273 {
274 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát41378452018-06-06 16:29:40 +0200275 if (parserContext.m_errorMsg.empty())
276 parserContext.m_errorMsg = "Expected " + x.which() + " here:";
277 return x3::error_handler_result::rethrow;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200278 }
279};
Václav Kubernátb61336d2018-05-28 17:35:03 +0200280
Václav Kubernát6797df02019-03-18 20:21:50 +0100281struct presenceContainerPath_class {
Václav Kubernátb61336d2018-05-28 17:35:03 +0200282 template <typename T, typename Iterator, typename Context>
283 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
284 {
285 auto& parserContext = x3::get<parser_context_tag>(context);
286 const auto& schema = parserContext.m_schema;
287 try {
Václav Kubernát744f57f2018-06-29 22:46:26 +0200288 boost::optional<std::string> module;
Václav Kubernát6797df02019-03-18 20:21:50 +0100289 if (ast.m_nodes.back().m_prefix)
290 module = ast.m_nodes.back().m_prefix.value().m_name;
291 container_ cont = boost::get<container_>(ast.m_nodes.back().m_suffix);
Václav Kubernát72749c62020-01-03 16:47:34 +0100292 auto location = pathWithoutLastNode(parserContext.currentSchemaPath());
Václav Kubernátb61336d2018-05-28 17:35:03 +0200293
Václav Kubernát744f57f2018-06-29 22:46:26 +0200294 if (!schema.isPresenceContainer(location, {module, cont.m_name})) {
Václav Kubernát41378452018-06-06 16:29:40 +0200295 parserContext.m_errorMsg = "This container is not a presence container.";
Václav Kubernátb61336d2018-05-28 17:35:03 +0200296 _pass(context) = false;
Václav Kubernátb61336d2018-05-28 17:35:03 +0200297 }
298 } catch (boost::bad_get&) {
Václav Kubernát41378452018-06-06 16:29:40 +0200299 parserContext.m_errorMsg = "This is not a container.";
Václav Kubernátb61336d2018-05-28 17:35:03 +0200300 _pass(context) = false;
Václav Kubernátb61336d2018-05-28 17:35:03 +0200301 }
302 }
Václav Kubernát6797df02019-03-18 20:21:50 +0100303};
Václav Kubernátb61336d2018-05-28 17:35:03 +0200304
Václav Kubernátf5f64f02019-03-19 17:15:47 +0100305struct listInstancePath_class {
306 template <typename T, typename Iterator, typename Context>
307 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
308 {
309 auto& parserContext = x3::get<parser_context_tag>(context);
310 if (ast.m_nodes.back().m_suffix.type() != typeid(listElement_)) {
311 parserContext.m_errorMsg = "This is not a list instance.";
312 _pass(context) = false;
313 }
314 }
315};
316
Václav Kubernát8028f942019-09-25 16:03:23 +0200317struct space_separator_class {
318 template <typename T, typename Iterator, typename Context>
319 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
320 {
321 auto& parserContext = x3::get<parser_context_tag>(context);
322 parserContext.m_suggestions.clear();
Václav Kubernáte69133a2019-11-01 19:01:34 +0100323 parserContext.m_completionSuffix.clear();
Václav Kubernát8028f942019-09-25 16:03:23 +0200324 }
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
Václav Kubernát72749c62020-01-03 16:47:34 +0100372 if (!schema.isModule(parserContext.currentSchemaPath(), ast.m_name)) {
Václav Kubernáteeb38842019-03-20 19:46:05 +0100373 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át72749c62020-01-03 16:47:34 +0100386 leaf_ leaf = boost::get<leaf_>(parserContext.currentSchemaPath().m_nodes.back().m_suffix);
387 schemaPath_ location = pathWithoutLastNode(parserContext.currentSchemaPath());
Václav Kubernáteeb38842019-03-20 19:46:05 +0100388 boost::optional<std::string> module;
Václav Kubernát72749c62020-01-03 16:47:34 +0100389 if (parserContext.currentSchemaPath().m_nodes.back().m_prefix)
390 module = parserContext.currentSchemaPath().m_nodes.back().m_prefix.value().m_name;
Václav Kubernáteeb38842019-03-20 19:46:05 +0100391 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
Václav Kubernát90de9502019-11-20 17:19:44 +0100398template <yang::LeafDataTypes TYPE>
Václav Kubernátebca2552018-06-08 19:06:02 +0200399struct leaf_data_base_class {
400 yang::LeafDataTypes m_type;
401
Ivona Oboňová88c78ca2019-07-02 18:40:07 +0200402 leaf_data_base_class()
403 : m_type(TYPE)
Václav Kubernátebca2552018-06-08 19:06:02 +0200404 {
405 }
406
407 template <typename T, typename Iterator, typename Context>
408 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
409 {
410 auto& parserContext = x3::get<parser_context_tag>(context);
411 auto& schema = parserContext.m_schema;
Václav Kubernát744f57f2018-06-29 22:46:26 +0200412 boost::optional<std::string> module;
Václav Kubernát72749c62020-01-03 16:47:34 +0100413 if (parserContext.currentSchemaPath().m_nodes.back().m_prefix)
414 module = parserContext.currentSchemaPath().m_nodes.back().m_prefix.value().m_name;
Václav Kubernátebca2552018-06-08 19:06:02 +0200415
Václav Kubernát72749c62020-01-03 16:47:34 +0100416 leaf_ leaf = boost::get<leaf_>(parserContext.currentSchemaPath().m_nodes.back().m_suffix);
417 schemaPath_ location = pathWithoutLastNode(parserContext.currentSchemaPath());
Václav Kubernátebca2552018-06-08 19:06:02 +0200418
Václav Kubernát6a8d1d92019-04-24 20:30:36 +0200419 auto type = schema.leafType(location, {module, leaf.m_name});
420 if (type == yang::LeafDataTypes::LeafRef) {
421 type = schema.leafrefBase(location, {module, leaf.m_name});
422 }
423 if (type != m_type) {
Václav Kubernátebca2552018-06-08 19:06:02 +0200424 _pass(context) = false;
425 }
426 }
427};
428
Ivona Oboňová88c78ca2019-07-02 18:40:07 +0200429struct leaf_data_binary_data_class;
430
431struct leaf_data_enum_class : leaf_data_base_class<yang::LeafDataTypes::Enum> {
432 using leaf_data_base_class::leaf_data_base_class;
Václav Kubernátebca2552018-06-08 19:06:02 +0200433
434 template <typename T, typename Iterator, typename Context>
435 void on_success(Iterator const& start, Iterator const& end, T& ast, Context const& context)
436 {
437 leaf_data_base_class::on_success(start, end, ast, context);
Václav Kubernáteeb38842019-03-20 19:46:05 +0100438 // Base class on_success cannot return for us, so we check if it failed the parser.
439 if (_pass(context) == false)
440 return;
Václav Kubernátebca2552018-06-08 19:06:02 +0200441 auto& parserContext = x3::get<parser_context_tag>(context);
442 auto& schema = parserContext.m_schema;
Václav Kubernát744f57f2018-06-29 22:46:26 +0200443 boost::optional<std::string> module;
Václav Kubernát72749c62020-01-03 16:47:34 +0100444 if (parserContext.currentSchemaPath().m_nodes.back().m_prefix)
445 module = parserContext.currentSchemaPath().m_nodes.back().m_prefix.value().m_name;
Václav Kubernátebca2552018-06-08 19:06:02 +0200446
Václav Kubernát72749c62020-01-03 16:47:34 +0100447 leaf_ leaf = boost::get<leaf_>(parserContext.currentSchemaPath().m_nodes.back().m_suffix);
448 schemaPath_ location = pathWithoutLastNode(parserContext.currentSchemaPath());
Václav Kubernátebca2552018-06-08 19:06:02 +0200449
Václav Kubernát744f57f2018-06-29 22:46:26 +0200450 if (!schema.leafEnumHasValue(location, {module, leaf.m_name}, ast.m_value)) {
Václav Kubernátebca2552018-06-08 19:06:02 +0200451 _pass(context) = false;
Václav Kubernát69710252019-11-15 17:08:30 +0100452
453 parserContext.m_errorMsg = "Expected an enum here. Allowed values:";
454 for (const auto& it : schema.enumValues(location, {module, leaf.m_name})) {
455 parserContext.m_errorMsg += " " + it;
456 }
Václav Kubernátebca2552018-06-08 19:06:02 +0200457 }
458 }
459};
460
Václav Kubernáteeb38842019-03-20 19:46:05 +0100461struct leaf_data_identityRef_data_class;
462
Ivona Oboňová88c78ca2019-07-02 18:40:07 +0200463struct leaf_data_identityRef_class : leaf_data_base_class<yang::LeafDataTypes::IdentityRef> {
464 using leaf_data_base_class::leaf_data_base_class;
Václav Kubernáteeb38842019-03-20 19:46:05 +0100465
466 template <typename T, typename Iterator, typename Context>
467 void on_success(Iterator const& start, Iterator const& end, T& ast, Context const& context)
468 {
469 // FIXME: can I reuse leaf_data_enum_class somehow..?
470 leaf_data_base_class::on_success(start, end, ast, context);
471 // Base class on_success cannot return for us, so we check if it failed the parser.
472 if (_pass(context) == false)
473 return;
474 auto& parserContext = x3::get<parser_context_tag>(context);
475 auto& schema = parserContext.m_schema;
476 boost::optional<std::string> module;
Václav Kubernát72749c62020-01-03 16:47:34 +0100477 if (parserContext.currentSchemaPath().m_nodes.back().m_prefix)
478 module = parserContext.currentSchemaPath().m_nodes.back().m_prefix.value().m_name;
Václav Kubernáteeb38842019-03-20 19:46:05 +0100479
Václav Kubernát72749c62020-01-03 16:47:34 +0100480 leaf_ leaf = boost::get<leaf_>(parserContext.currentSchemaPath().m_nodes.back().m_suffix);
481 schemaPath_ location = pathWithoutLastNode(parserContext.currentSchemaPath());
Václav Kubernáteeb38842019-03-20 19:46:05 +0100482
483 ModuleValuePair pair;
484 if (ast.m_prefix) {
485 pair.first = ast.m_prefix.get().m_name;
486 }
487 pair.second = ast.m_value;
488
489 if (!schema.leafIdentityIsValid(location, {module, leaf.m_name}, pair)) {
490 _pass(context) = false;
491 }
492 }
493};
494
Václav Kubernát07204242018-06-04 18:12:09 +0200495struct set_class {
Václav Kubernát07204242018-06-04 18:12:09 +0200496 template <typename Iterator, typename Exception, typename Context>
497 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const& x, Context const& context)
498 {
499 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát41378452018-06-06 16:29:40 +0200500 if (parserContext.m_errorMsg.empty())
501 parserContext.m_errorMsg = "Expected " + x.which() + " here:";
502 return x3::error_handler_result::rethrow;
Václav Kubernát07204242018-06-04 18:12:09 +0200503 }
504};
505
Václav Kubernát812ee282018-08-30 17:10:03 +0200506struct commit_class;
507
Václav Kubernát054cc992019-02-21 14:23:52 +0100508struct help_class;
509
Václav Kubernátb6ff0b62018-08-30 16:14:53 +0200510struct get_class;
511
Václav Kubernátb61336d2018-05-28 17:35:03 +0200512struct command_class {
513 template <typename Iterator, typename Exception, typename Context>
514 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const& x, Context const& context)
515 {
516 auto& parserContext = x3::get<parser_context_tag>(context);
517 auto& error_handler = x3::get<x3::error_handler_tag>(context).get();
Václav Kubernát41378452018-06-06 16:29:40 +0200518 if (parserContext.m_errorMsg.empty()) {
519 parserContext.m_errorMsg = "Unknown command.";
520 }
521 error_handler(x.where(), parserContext.m_errorMsg);
Václav Kubernátb61336d2018-05-28 17:35:03 +0200522 return x3::error_handler_result::fail;
523 }
524};
Václav Kubernát5c75b252018-10-10 18:33:47 +0200525
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100526struct initializePath_class {
Václav Kubernát5c75b252018-10-10 18:33:47 +0200527 template <typename T, typename Iterator, typename Context>
528 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
529 {
530 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát72749c62020-01-03 16:47:34 +0100531 parserContext.resetPath();
Václav Kubernát5c75b252018-10-10 18:33:47 +0200532 parserContext.m_tmpListKeys.clear();
533 parserContext.m_tmpListName.clear();
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100534 parserContext.m_suggestions.clear();
Václav Kubernát5c75b252018-10-10 18:33:47 +0200535 }
536};
Václav Kubernátd6fd2492018-11-19 15:11:16 +0100537
538struct trailingSlash_class;
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100539
540struct createPathSuggestions_class {
541 template <typename T, typename Iterator, typename Context>
542 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
543 {
544 auto& parserContext = x3::get<parser_context_tag>(context);
545 const auto& schema = parserContext.m_schema;
546
547 parserContext.m_completionIterator = begin;
Václav Kubernát72749c62020-01-03 16:47:34 +0100548 auto suggestions = schema.childNodes(parserContext.currentSchemaPath(), Recursion::NonRecursive);
Václav Kubernáte69133a2019-11-01 19:01:34 +0100549 std::set<std::string> suffixesAdded;
550 std::transform(suggestions.begin(), suggestions.end(),
551 std::inserter(suffixesAdded, suffixesAdded.end()),
552 [&parserContext, &schema] (auto it) {
553 ModuleNodePair node;
554 if (auto colonPos = it.find(":"); colonPos != it.npos) {
555 node.first = it.substr(0, colonPos);
556 node.second = it.substr(colonPos + 1, node.second.npos);
557 } else {
558 node.first = boost::none;
559 node.second = it;
560 }
561
Václav Kubernát72749c62020-01-03 16:47:34 +0100562 if (schema.isLeaf(parserContext.currentSchemaPath(), node)) {
Václav Kubernáte69133a2019-11-01 19:01:34 +0100563 return it + " ";
564 }
Václav Kubernát72749c62020-01-03 16:47:34 +0100565 if (schema.isContainer(parserContext.currentSchemaPath(), node)) {
Václav Kubernáte69133a2019-11-01 19:01:34 +0100566 return it + "/";
567 }
Václav Kubernát72749c62020-01-03 16:47:34 +0100568 if (schema.isList(parserContext.currentSchemaPath(), node)) {
Václav Kubernáte69133a2019-11-01 19:01:34 +0100569 return it + "[";
570 }
571 return it;
572 });
573 parserContext.m_suggestions = suffixesAdded;
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100574 }
575};
Václav Kubernát329c6c32019-02-06 16:41:53 +0100576
577std::set<std::string> generateMissingKeyCompletionSet(std::set<std::string> keysNeeded, std::set<std::string> currentSet);
578
579struct createKeySuggestions_class {
580 template <typename T, typename Iterator, typename Context>
581 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
582 {
583 auto& parserContext = x3::get<parser_context_tag>(context);
584 const auto& schema = parserContext.m_schema;
585
586 parserContext.m_completionIterator = begin;
587
Václav Kubernát72749c62020-01-03 16:47:34 +0100588 const auto& keysNeeded = schema.listKeys(parserContext.currentSchemaPath(), {parserContext.m_curModule, parserContext.m_tmpListName});
Václav Kubernát329c6c32019-02-06 16:41:53 +0100589 parserContext.m_suggestions = generateMissingKeyCompletionSet(keysNeeded, parserContext.m_tmpListKeys);
590 }
591};
592
593struct suggestKeysEnd_class {
594 template <typename T, typename Iterator, typename Context>
595 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
596 {
597 auto& parserContext = x3::get<parser_context_tag>(context);
598 const auto& schema = parserContext.m_schema;
599
600 parserContext.m_completionIterator = begin;
Václav Kubernát72749c62020-01-03 16:47:34 +0100601 const auto& keysNeeded = schema.listKeys(parserContext.currentSchemaPath(), {parserContext.m_curModule, parserContext.m_tmpListName});
Václav Kubernát329c6c32019-02-06 16:41:53 +0100602 if (generateMissingKeyCompletionSet(keysNeeded, parserContext.m_tmpListKeys).empty()) {
603 parserContext.m_suggestions = {"]/"};
604 } else {
Václav Kubernát4c325482019-04-11 17:51:55 +0200605 parserContext.m_suggestions = {"]["};
Václav Kubernát329c6c32019-02-06 16:41:53 +0100606 }
607 }
608};
Václav Kubernát57272422019-02-08 12:48:24 +0100609
610struct commandNamesVisitor {
611 template <typename T>
612 auto operator()(boost::type<T>)
613 {
614 return T::name;
615 }
616};
617
618struct createCommandSuggestions_class {
619 template <typename T, typename Iterator, typename Context>
620 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
621 {
622 auto& parserContext = x3::get<parser_context_tag>(context);
623 parserContext.m_completionIterator = begin;
624
625 parserContext.m_suggestions.clear();
626 boost::mpl::for_each<CommandTypes, boost::type<boost::mpl::_>>([&parserContext](auto cmd) {
627 parserContext.m_suggestions.emplace(commandNamesVisitor()(cmd));
628 });
629 }
630};
Václav Kubernátac035d62019-02-18 10:59:08 +0100631
632struct completing_class {
633 template <typename T, typename Iterator, typename Context>
634 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
635 {
636 auto& parserContext = x3::get<parser_context_tag>(context);
637
638 if (!parserContext.m_completing)
639 _pass(context) = false;
640 }
641};
Václav Kubernát989b5de2019-02-20 16:28:35 +0100642
643struct createEnumSuggestions_class {
644 template <typename T, typename Iterator, typename Context>
645 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
646 {
647 auto& parserContext = x3::get<parser_context_tag>(context);
648 parserContext.m_completionIterator = begin;
649 const Schema& schema = parserContext.m_schema;
650
651 boost::optional<std::string> module;
Václav Kubernát72749c62020-01-03 16:47:34 +0100652 if (parserContext.currentSchemaPath().m_nodes.back().m_prefix)
653 module = parserContext.currentSchemaPath().m_nodes.back().m_prefix.value().m_name;
Václav Kubernát989b5de2019-02-20 16:28:35 +0100654
Václav Kubernát72749c62020-01-03 16:47:34 +0100655 leaf_ leaf = boost::get<leaf_>(parserContext.currentSchemaPath().m_nodes.back().m_suffix);
656 schemaPath_ location = pathWithoutLastNode(parserContext.currentSchemaPath());
Václav Kubernát989b5de2019-02-20 16:28:35 +0100657
Václav Kubernáteeb38842019-03-20 19:46:05 +0100658 // Only generate completions if the type is enum so that we don't
659 // overwrite some other completions.
660 if (schema.leafType(location, {module, leaf.m_name}) == yang::LeafDataTypes::Enum)
661 parserContext.m_suggestions = schema.enumValues(location, {module, leaf.m_name});
662 }
663};
664
665// FIXME: can I reuse createEnumSuggestions?
666struct createIdentitySuggestions_class {
667 template <typename T, typename Iterator, typename Context>
668 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
669 {
670 auto& parserContext = x3::get<parser_context_tag>(context);
671 parserContext.m_completionIterator = begin;
672 const Schema& schema = parserContext.m_schema;
673
674 boost::optional<std::string> module;
Václav Kubernát72749c62020-01-03 16:47:34 +0100675 if (parserContext.currentSchemaPath().m_nodes.back().m_prefix)
676 module = parserContext.currentSchemaPath().m_nodes.back().m_prefix.value().m_name;
Václav Kubernáteeb38842019-03-20 19:46:05 +0100677
Václav Kubernát72749c62020-01-03 16:47:34 +0100678 leaf_ leaf = boost::get<leaf_>(parserContext.currentSchemaPath().m_nodes.back().m_suffix);
679 schemaPath_ location = pathWithoutLastNode(parserContext.currentSchemaPath());
Václav Kubernáteeb38842019-03-20 19:46:05 +0100680
681 // Only generate completions if the type is identityref so that we
682 // don't overwrite some other completions.
683 if (schema.leafType(location, {module, leaf.m_name}) == yang::LeafDataTypes::IdentityRef)
684 parserContext.m_suggestions = schema.validIdentities(location, {module, leaf.m_name}, Prefixes::WhenNeeded);
Václav Kubernát989b5de2019-02-20 16:28:35 +0100685 }
686};