blob: 6ecfbc5bac53357ab7e25fc1e1cc623e58b000dd [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át0a2a2e82018-05-11 13:59:12 +020028
29 if (parserContext.m_tmpListKeys.find(ast.first) != parserContext.m_tmpListKeys.end()) {
30 _pass(context) = false;
31 parserContext.m_errorMsg = "Key \"" + ast.first + "\" was entered more than once.";
Václav Kubernát41378452018-06-06 16:29:40 +020032 } else {
Václav Kubernát43908fb2020-01-02 19:05:51 +010033 parserContext.m_tmpListKeys.insert({ast.first, ast.second});
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020034 }
35 }
Václav Kubernát41378452018-06-06 16:29:40 +020036
37 template <typename Iterator, typename Exception, typename Context>
38 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
39 {
40 auto& parserContext = x3::get<parser_context_tag>(context);
41 parserContext.m_errorMsg = "Error parsing key values here:";
42 return x3::error_handler_result::rethrow;
43 }
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020044};
Václav Kubernát41378452018-06-06 16:29:40 +020045
Václav Kubernát744f57f2018-06-29 22:46:26 +020046struct node_identifier_class {
47 template <typename T, typename Iterator, typename Context>
48 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
49 {
50 auto& parserContext = x3::get<parser_context_tag>(context);
51
52 if (!parserContext.m_topLevelModulePresent) {
53 if (parserContext.m_errorMsg.empty())
54 parserContext.m_errorMsg = "You have to specify a top level module.";
55 _pass(context) = false;
56 }
57 }
58};
59
Václav Kubernát7707cae2020-01-16 12:04:53 +010060struct key_identifier_class {
61 template <typename T, typename Iterator, typename Context>
62 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
63 {
64 auto& parserContext = x3::get<parser_context_tag>(context);
65 const Schema& schema = parserContext.m_schema;
66 schemaPath_ location = parserContext.currentSchemaPath();
67 ModuleNodePair list{parserContext.m_curModule, parserContext.m_tmpListName};
68
69 if (schema.listHasKey(location, list, ast)) {
70 schemaNode_ listNode;
Václav Kubernát43908fb2020-01-02 19:05:51 +010071 listNode.m_prefix = parserContext.m_curModule.flat_map([] (auto mod) { return boost::optional<module_>{{mod}}; });;
Václav Kubernát7707cae2020-01-16 12:04:53 +010072 listNode.m_suffix = list_{parserContext.m_tmpListName};
73 location.m_nodes.push_back(listNode);
74 parserContext.m_tmpListKeyLeafPath.m_location = location;
Václav Kubernát43908fb2020-01-02 19:05:51 +010075 parserContext.m_tmpListKeyLeafPath.m_node = { parserContext.m_curModule, ast };
Václav Kubernát7707cae2020-01-16 12:04:53 +010076 } else {
77 parserContext.m_errorMsg = parserContext.m_tmpListName + " is not indexed by \"" + ast + "\".";
78 _pass(context) = false;
79 }
80 }
81};
Václav Kubernát89728d82018-09-13 16:28:28 +020082
Václav Kubernát744f57f2018-06-29 22:46:26 +020083struct module_identifier_class;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020084
85struct listPrefix_class {
86 template <typename T, typename Iterator, typename Context>
87 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
88 {
89 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát48fc3832018-05-28 14:21:22 +020090 const Schema& schema = parserContext.m_schema;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020091
Václav Kubernát72749c62020-01-03 16:47:34 +010092 if (schema.isList(parserContext.currentSchemaPath(), {parserContext.m_curModule, ast})) {
Václav Kubernát0a2a2e82018-05-11 13:59:12 +020093 parserContext.m_tmpListName = ast;
94 } else {
95 _pass(context) = false;
96 }
97 }
98};
99
100struct listSuffix_class {
101 template <typename T, typename Iterator, typename Context>
102 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
103 {
104 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát48fc3832018-05-28 14:21:22 +0200105 const Schema& schema = parserContext.m_schema;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200106
Václav Kubernát72749c62020-01-03 16:47:34 +0100107 const auto& keysNeeded = schema.listKeys(parserContext.currentSchemaPath(), {parserContext.m_curModule, parserContext.m_tmpListName});
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200108 std::set<std::string> keysSupplied;
109 for (const auto& it : ast)
110 keysSupplied.insert(it.first);
111
112 if (keysNeeded != keysSupplied) {
113 parserContext.m_errorMsg = "Not enough keys for " + parserContext.m_tmpListName + ". " +
114 "These keys were not supplied:";
115 std::set<std::string> missingKeys;
116 std::set_difference(keysNeeded.begin(), keysNeeded.end(),
117 keysSupplied.begin(), keysSupplied.end(),
118 std::inserter(missingKeys, missingKeys.end()));
119
120 for (const auto& it : missingKeys)
121 parserContext.m_errorMsg += " " + it;
122 parserContext.m_errorMsg += ".";
123
124 _pass(context) = false;
125 }
126 }
Václav Kubernát41378452018-06-06 16:29:40 +0200127
128 template <typename Iterator, typename Exception, typename Context>
129 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
130 {
131 auto& parserContext = x3::get<parser_context_tag>(context);
132 if (parserContext.m_errorMsg.empty())
133 parserContext.m_errorMsg = "Expecting ']' here:";
134 return x3::error_handler_result::rethrow;
Václav Kubernát41378452018-06-06 16:29:40 +0200135 }
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200136};
137struct listElement_class {
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200138 template <typename Iterator, typename Exception, typename Context>
Václav Kubernát41378452018-06-06 16:29:40 +0200139 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200140 {
141 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát41378452018-06-06 16:29:40 +0200142 if (parserContext.m_errorMsg.empty()) {
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200143 return x3::error_handler_result::fail;
Václav Kubernát41378452018-06-06 16:29:40 +0200144 } else {
145 return x3::error_handler_result::rethrow;
146 }
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200147 }
148};
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200149struct list_class {
150 template <typename T, typename Iterator, typename Context>
151 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
152 {
153 auto& parserContext = x3::get<parser_context_tag>(context);
154 const Schema& schema = parserContext.m_schema;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200155
Václav Kubernát72749c62020-01-03 16:47:34 +0100156 if (!schema.isList(parserContext.currentSchemaPath(), {parserContext.m_curModule, ast.m_name})) {
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200157 _pass(context) = false;
158 }
159 }
160};
Václav Kubernát60d6f292018-05-25 09:45:32 +0200161struct nodeup_class {
162 template <typename T, typename Iterator, typename Context>
163 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
164 {
165 auto& parserContext = x3::get<parser_context_tag>(context);
166
Václav Kubernát72749c62020-01-03 16:47:34 +0100167 if (parserContext.currentSchemaPath().m_nodes.empty())
Václav Kubernát60d6f292018-05-25 09:45:32 +0200168 _pass(context) = false;
Václav Kubernát60d6f292018-05-25 09:45:32 +0200169 }
170};
171
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200172struct container_class {
173 template <typename T, typename Iterator, typename Context>
174 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
175 {
176 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát48fc3832018-05-28 14:21:22 +0200177 const auto& schema = parserContext.m_schema;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200178
Václav Kubernát72749c62020-01-03 16:47:34 +0100179 if (!schema.isContainer(parserContext.currentSchemaPath(), {parserContext.m_curModule, ast.m_name}))
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200180 _pass(context) = false;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200181 }
182};
183
Václav Kubernát07204242018-06-04 18:12:09 +0200184struct leaf_class {
185 template <typename T, typename Iterator, typename Context>
186 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
187 {
188 auto& parserContext = x3::get<parser_context_tag>(context);
189 const auto& schema = parserContext.m_schema;
190
Václav Kubernát72749c62020-01-03 16:47:34 +0100191 if (!schema.isLeaf(parserContext.currentSchemaPath(), {parserContext.m_curModule, ast.m_name}))
Václav Kubernát744f57f2018-06-29 22:46:26 +0200192 _pass(context) = false;
193 }
194};
195
Václav Kubernát744f57f2018-06-29 22:46:26 +0200196struct module_class {
197 template <typename T, typename Iterator, typename Context>
198 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
199 {
200 auto& parserContext = x3::get<parser_context_tag>(context);
201 const auto& schema = parserContext.m_schema;
202
Václav Kubernát75877de2019-11-20 17:43:02 +0100203 if (schema.isModule(ast.m_name)) {
Václav Kubernát744f57f2018-06-29 22:46:26 +0200204 parserContext.m_curModule = ast.m_name;
205 parserContext.m_topLevelModulePresent = true;
Václav Kubernát07204242018-06-04 18:12:09 +0200206 } else {
Václav Kubernát744f57f2018-06-29 22:46:26 +0200207 parserContext.m_errorMsg = "Invalid module name.";
Václav Kubernát07204242018-06-04 18:12:09 +0200208 _pass(context) = false;
209 }
210 }
211};
212
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200213struct schemaNode_class {
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200214 template <typename T, typename Iterator, typename Context>
Václav Kubernát744f57f2018-06-29 22:46:26 +0200215 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200216 {
Václav Kubernát744f57f2018-06-29 22:46:26 +0200217 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát72749c62020-01-03 16:47:34 +0100218 parserContext.pushPathFragment(ast);
219 parserContext.m_curModule = boost::none;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200220 }
Václav Kubernát744f57f2018-06-29 22:46:26 +0200221};
Václav Kubernát07204242018-06-04 18:12:09 +0200222
Václav Kubernát39ae9592019-02-05 17:35:16 +0100223struct dataNodeList_class {
224 template <typename T, typename Iterator, typename Context>
225 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
226 {
227 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát72749c62020-01-03 16:47:34 +0100228 parserContext.pushPathFragment(ast);
Václav Kubernát39ae9592019-02-05 17:35:16 +0100229 }
230};
Václav Kubernát5c75b252018-10-10 18:33:47 +0200231
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200232struct dataNode_class {
233 template <typename T, typename Iterator, typename Context>
234 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
235 {
236 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát72749c62020-01-03 16:47:34 +0100237 parserContext.pushPathFragment(ast);
238 parserContext.m_curModule = boost::none;
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200239 }
240};
241
Václav Kubernát37171a12018-08-31 17:01:48 +0200242struct absoluteStart_class {
243 template <typename T, typename Iterator, typename Context>
244 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
245 {
246 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát72749c62020-01-03 16:47:34 +0100247 parserContext.clearPath();
Václav Kubernát37171a12018-08-31 17:01:48 +0200248 }
249};
250
Václav Kubernát5c75b252018-10-10 18:33:47 +0200251struct dataNodesListEnd_class;
252
253struct dataPathListEnd_class;
254
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200255struct dataPath_class {
256 template <typename Iterator, typename Exception, typename Context>
257 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
258 {
259 auto& parserContext = x3::get<parser_context_tag>(context);
260 if (parserContext.m_errorMsg.empty()) {
261 parserContext.m_errorMsg = "Expected path.";
262 return x3::error_handler_result::fail;
263 } else {
264 return x3::error_handler_result::rethrow;
265 }
266 }
267};
268
269struct schemaPath_class {
Václav Kubernát07204242018-06-04 18:12:09 +0200270 template <typename Iterator, typename Exception, typename Context>
Václav Kubernát41378452018-06-06 16:29:40 +0200271 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
Václav Kubernát07204242018-06-04 18:12:09 +0200272 {
273 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát41378452018-06-06 16:29:40 +0200274 if (parserContext.m_errorMsg.empty()) {
275 parserContext.m_errorMsg = "Expected path.";
Václav Kubernát07204242018-06-04 18:12:09 +0200276 return x3::error_handler_result::fail;
Václav Kubernát41378452018-06-06 16:29:40 +0200277 } else {
278 return x3::error_handler_result::rethrow;
279 }
Václav Kubernát07204242018-06-04 18:12:09 +0200280 }
281};
282
Václav Kubernát6d791432018-10-25 16:00:35 +0200283struct discard_class;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200284
Václav Kubernát11afac72018-07-18 14:59:53 +0200285struct ls_class;
286
Václav Kubernát744f57f2018-06-29 22:46:26 +0200287struct cd_class {
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200288 template <typename Iterator, typename Exception, typename Context>
289 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const& x, Context const& context)
290 {
291 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát41378452018-06-06 16:29:40 +0200292 if (parserContext.m_errorMsg.empty())
293 parserContext.m_errorMsg = "Expected " + x.which() + " here:";
294 return x3::error_handler_result::rethrow;
Václav Kubernát0a2a2e82018-05-11 13:59:12 +0200295 }
296};
Václav Kubernátb61336d2018-05-28 17:35:03 +0200297
Václav Kubernát6797df02019-03-18 20:21:50 +0100298struct presenceContainerPath_class {
Václav Kubernátb61336d2018-05-28 17:35:03 +0200299 template <typename T, typename Iterator, typename Context>
300 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
301 {
302 auto& parserContext = x3::get<parser_context_tag>(context);
303 const auto& schema = parserContext.m_schema;
304 try {
Václav Kubernát744f57f2018-06-29 22:46:26 +0200305 boost::optional<std::string> module;
Václav Kubernát6797df02019-03-18 20:21:50 +0100306 if (ast.m_nodes.back().m_prefix)
307 module = ast.m_nodes.back().m_prefix.value().m_name;
308 container_ cont = boost::get<container_>(ast.m_nodes.back().m_suffix);
Václav Kubernát72749c62020-01-03 16:47:34 +0100309 auto location = pathWithoutLastNode(parserContext.currentSchemaPath());
Václav Kubernátb61336d2018-05-28 17:35:03 +0200310
Václav Kubernát744f57f2018-06-29 22:46:26 +0200311 if (!schema.isPresenceContainer(location, {module, cont.m_name})) {
Václav Kubernát41378452018-06-06 16:29:40 +0200312 parserContext.m_errorMsg = "This container is not a presence 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 } catch (boost::bad_get&) {
Václav Kubernát41378452018-06-06 16:29:40 +0200316 parserContext.m_errorMsg = "This is not a container.";
Václav Kubernátb61336d2018-05-28 17:35:03 +0200317 _pass(context) = false;
Václav Kubernátb61336d2018-05-28 17:35:03 +0200318 }
319 }
Václav Kubernát6797df02019-03-18 20:21:50 +0100320};
Václav Kubernátb61336d2018-05-28 17:35:03 +0200321
Václav Kubernátf5f64f02019-03-19 17:15:47 +0100322struct listInstancePath_class {
323 template <typename T, typename Iterator, typename Context>
324 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
325 {
326 auto& parserContext = x3::get<parser_context_tag>(context);
327 if (ast.m_nodes.back().m_suffix.type() != typeid(listElement_)) {
328 parserContext.m_errorMsg = "This is not a list instance.";
329 _pass(context) = false;
330 }
331 }
332};
333
Václav Kubernát8028f942019-09-25 16:03:23 +0200334struct space_separator_class {
335 template <typename T, typename Iterator, typename Context>
336 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
337 {
338 auto& parserContext = x3::get<parser_context_tag>(context);
339 parserContext.m_suggestions.clear();
Václav Kubernát1ed4aa32020-01-23 13:13:28 +0100340 parserContext.m_completionIterator = boost::none;
Václav Kubernáte69133a2019-11-01 19:01:34 +0100341 parserContext.m_completionSuffix.clear();
Václav Kubernát8028f942019-09-25 16:03:23 +0200342 }
343};
344
Václav Kubernát6797df02019-03-18 20:21:50 +0100345struct create_class {
Václav Kubernátb61336d2018-05-28 17:35:03 +0200346 template <typename Iterator, typename Exception, typename Context>
Václav Kubernát41378452018-06-06 16:29:40 +0200347 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
Václav Kubernátb61336d2018-05-28 17:35:03 +0200348 {
349 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát41378452018-06-06 16:29:40 +0200350 if (parserContext.m_errorMsg.empty())
351 parserContext.m_errorMsg = "Couldn't parse create/delete command.";
352 return x3::error_handler_result::rethrow;
Václav Kubernátb61336d2018-05-28 17:35:03 +0200353 }
354};
355
Václav Kubernát6797df02019-03-18 20:21:50 +0100356struct delete_class {
357 template <typename Iterator, typename Exception, typename Context>
358 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
359 {
360 auto& parserContext = x3::get<parser_context_tag>(context);
361 if (parserContext.m_errorMsg.empty())
362 parserContext.m_errorMsg = "Couldn't parse create/delete command.";
363 return x3::error_handler_result::rethrow;
364 }
Václav Kubernátb61336d2018-05-28 17:35:03 +0200365};
366
Václav Kubernát0b0272f2018-06-13 14:13:08 +0200367struct leaf_path_class {
368 template <typename T, typename Iterator, typename Context>
Václav Kubernát7707cae2020-01-16 12:04:53 +0100369 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
Václav Kubernát0b0272f2018-06-13 14:13:08 +0200370 {
371 auto& parserContext = x3::get<parser_context_tag>(context);
372 try {
Václav Kubernát7707cae2020-01-16 12:04:53 +0100373 auto lastNode = parserContext.currentSchemaPath().m_nodes.back();
374 auto leaf = boost::get<leaf_>(lastNode.m_suffix);
375 auto location = pathWithoutLastNode(parserContext.currentSchemaPath());
376 ModuleNodePair node{lastNode.m_prefix.flat_map([](const auto& it) { return boost::optional<std::string>{it.m_name}; }), leaf.m_name};
377
378 parserContext.m_tmpListKeyLeafPath.m_location = location;
379 parserContext.m_tmpListKeyLeafPath.m_node = node;
380
Václav Kubernát0b0272f2018-06-13 14:13:08 +0200381 } catch (boost::bad_get&) {
382 parserContext.m_errorMsg = "This is not a path to leaf.";
383 _pass(context) = false;
384 }
385 }
386};
387
Václav Kubernáteeb38842019-03-20 19:46:05 +0100388// This handler only checks if the module exists
389// It doesn't set any ParserContext flags (except the error message)
390struct data_module_prefix_class {
391 template <typename T, typename Iterator, typename Context>
392 void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
393 {
394 auto& parserContext = x3::get<parser_context_tag>(context);
395 const auto& schema = parserContext.m_schema;
396
Václav Kubernát72749c62020-01-03 16:47:34 +0100397 if (!schema.isModule(parserContext.currentSchemaPath(), ast.m_name)) {
Václav Kubernáteeb38842019-03-20 19:46:05 +0100398 parserContext.m_errorMsg = "Invalid module name.";
399 _pass(context) = false;
400 }
401 }
402};
403
Václav Kubernátebca2552018-06-08 19:06:02 +0200404struct leaf_data_class {
Václav Kubernát0b0272f2018-06-13 14:13:08 +0200405 template <typename Iterator, typename Exception, typename Context>
406 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const&, Context const& context)
407 {
408 auto& parserContext = x3::get<parser_context_tag>(context);
409 auto& schema = parserContext.m_schema;
410 if (parserContext.m_errorMsg.empty()) {
Václav Kubernát7707cae2020-01-16 12:04:53 +0100411 parserContext.m_errorMsg = "leaf data type mismatch: Expected " +
412 leafDataTypeToString(schema.leafType(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node)) + " here:";
Václav Kubernát0b0272f2018-06-13 14:13:08 +0200413 return x3::error_handler_result::fail;
414 }
415 return x3::error_handler_result::rethrow;
416 }
Václav Kubernátebca2552018-06-08 19:06:02 +0200417};
418
Václav Kubernát90de9502019-11-20 17:19:44 +0100419template <yang::LeafDataTypes TYPE>
Václav Kubernátebca2552018-06-08 19:06:02 +0200420struct leaf_data_base_class {
421 yang::LeafDataTypes m_type;
422
Ivona Oboňová88c78ca2019-07-02 18:40:07 +0200423 leaf_data_base_class()
424 : m_type(TYPE)
Václav Kubernátebca2552018-06-08 19:06:02 +0200425 {
426 }
427
428 template <typename T, typename Iterator, typename Context>
429 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
430 {
431 auto& parserContext = x3::get<parser_context_tag>(context);
432 auto& schema = parserContext.m_schema;
433
Václav Kubernát7707cae2020-01-16 12:04:53 +0100434 auto type = schema.leafType(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node);
Václav Kubernát6a8d1d92019-04-24 20:30:36 +0200435 if (type == yang::LeafDataTypes::LeafRef) {
Václav Kubernát7707cae2020-01-16 12:04:53 +0100436 type = schema.leafrefBase(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node);
Václav Kubernát6a8d1d92019-04-24 20:30:36 +0200437 }
Václav Kubernát7707cae2020-01-16 12:04:53 +0100438
Václav Kubernát6a8d1d92019-04-24 20:30:36 +0200439 if (type != m_type) {
Václav Kubernátebca2552018-06-08 19:06:02 +0200440 _pass(context) = false;
441 }
442 }
443};
444
Ivona Oboňová88c78ca2019-07-02 18:40:07 +0200445struct leaf_data_binary_data_class;
446
447struct leaf_data_enum_class : leaf_data_base_class<yang::LeafDataTypes::Enum> {
448 using leaf_data_base_class::leaf_data_base_class;
Václav Kubernátebca2552018-06-08 19:06:02 +0200449
450 template <typename T, typename Iterator, typename Context>
451 void on_success(Iterator const& start, Iterator const& end, T& ast, Context const& context)
452 {
453 leaf_data_base_class::on_success(start, end, ast, context);
Václav Kubernáteeb38842019-03-20 19:46:05 +0100454 // Base class on_success cannot return for us, so we check if it failed the parser.
455 if (_pass(context) == false)
456 return;
Václav Kubernátebca2552018-06-08 19:06:02 +0200457 auto& parserContext = x3::get<parser_context_tag>(context);
458 auto& schema = parserContext.m_schema;
459
Václav Kubernát7707cae2020-01-16 12:04:53 +0100460 if (!schema.leafEnumHasValue(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node, ast.m_value)) {
Václav Kubernátebca2552018-06-08 19:06:02 +0200461 _pass(context) = false;
Václav Kubernát777704d2020-01-15 18:48:06 +0100462 parserContext.m_errorMsg = "leaf data type mismatch: Expected an enum here. Allowed values:";
Václav Kubernát7707cae2020-01-16 12:04:53 +0100463 for (const auto& it : schema.enumValues(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node)) {
Václav Kubernát69710252019-11-15 17:08:30 +0100464 parserContext.m_errorMsg += " " + it;
465 }
Václav Kubernátebca2552018-06-08 19:06:02 +0200466 }
467 }
468};
469
Václav Kubernáteeb38842019-03-20 19:46:05 +0100470struct leaf_data_identityRef_data_class;
471
Ivona Oboňová88c78ca2019-07-02 18:40:07 +0200472struct leaf_data_identityRef_class : leaf_data_base_class<yang::LeafDataTypes::IdentityRef> {
473 using leaf_data_base_class::leaf_data_base_class;
Václav Kubernáteeb38842019-03-20 19:46:05 +0100474
475 template <typename T, typename Iterator, typename Context>
476 void on_success(Iterator const& start, Iterator const& end, T& ast, Context const& context)
477 {
478 // FIXME: can I reuse leaf_data_enum_class somehow..?
479 leaf_data_base_class::on_success(start, end, ast, context);
480 // Base class on_success cannot return for us, so we check if it failed the parser.
481 if (_pass(context) == false)
482 return;
483 auto& parserContext = x3::get<parser_context_tag>(context);
484 auto& schema = parserContext.m_schema;
Václav Kubernáteeb38842019-03-20 19:46:05 +0100485
486 ModuleValuePair pair;
487 if (ast.m_prefix) {
488 pair.first = ast.m_prefix.get().m_name;
489 }
490 pair.second = ast.m_value;
491
Václav Kubernát7707cae2020-01-16 12:04:53 +0100492 if (!schema.leafIdentityIsValid(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node, pair)) {
Václav Kubernáteeb38842019-03-20 19:46:05 +0100493 _pass(context) = false;
494 }
495 }
496};
497
Václav Kubernát07204242018-06-04 18:12:09 +0200498struct set_class {
Václav Kubernát07204242018-06-04 18:12:09 +0200499 template <typename Iterator, typename Exception, typename Context>
500 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const& x, Context const& context)
501 {
502 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát41378452018-06-06 16:29:40 +0200503 if (parserContext.m_errorMsg.empty())
504 parserContext.m_errorMsg = "Expected " + x.which() + " here:";
505 return x3::error_handler_result::rethrow;
Václav Kubernát07204242018-06-04 18:12:09 +0200506 }
507};
508
Václav Kubernát812ee282018-08-30 17:10:03 +0200509struct commit_class;
510
Václav Kubernát054cc992019-02-21 14:23:52 +0100511struct help_class;
512
Václav Kubernátb6ff0b62018-08-30 16:14:53 +0200513struct get_class;
514
Václav Kubernátb61336d2018-05-28 17:35:03 +0200515struct command_class {
516 template <typename Iterator, typename Exception, typename Context>
517 x3::error_handler_result on_error(Iterator&, Iterator const&, Exception const& x, Context const& context)
518 {
519 auto& parserContext = x3::get<parser_context_tag>(context);
520 auto& error_handler = x3::get<x3::error_handler_tag>(context).get();
Václav Kubernát41378452018-06-06 16:29:40 +0200521 if (parserContext.m_errorMsg.empty()) {
522 parserContext.m_errorMsg = "Unknown command.";
523 }
524 error_handler(x.where(), parserContext.m_errorMsg);
Václav Kubernátb61336d2018-05-28 17:35:03 +0200525 return x3::error_handler_result::fail;
526 }
527};
Václav Kubernát5c75b252018-10-10 18:33:47 +0200528
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100529struct initializePath_class {
Václav Kubernát5c75b252018-10-10 18:33:47 +0200530 template <typename T, typename Iterator, typename Context>
531 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
532 {
533 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát72749c62020-01-03 16:47:34 +0100534 parserContext.resetPath();
Václav Kubernát5c75b252018-10-10 18:33:47 +0200535 parserContext.m_tmpListKeys.clear();
536 parserContext.m_tmpListName.clear();
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100537 parserContext.m_suggestions.clear();
Václav Kubernát5c75b252018-10-10 18:33:47 +0200538 }
539};
Václav Kubernátd6fd2492018-11-19 15:11:16 +0100540
541struct trailingSlash_class;
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100542
543struct createPathSuggestions_class {
544 template <typename T, typename Iterator, typename Context>
545 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
546 {
547 auto& parserContext = x3::get<parser_context_tag>(context);
548 const auto& schema = parserContext.m_schema;
549
550 parserContext.m_completionIterator = begin;
Václav Kubernát72749c62020-01-03 16:47:34 +0100551 auto suggestions = schema.childNodes(parserContext.currentSchemaPath(), Recursion::NonRecursive);
Václav Kubernáte69133a2019-11-01 19:01:34 +0100552 std::set<std::string> suffixesAdded;
553 std::transform(suggestions.begin(), suggestions.end(),
554 std::inserter(suffixesAdded, suffixesAdded.end()),
555 [&parserContext, &schema] (auto it) {
556 ModuleNodePair node;
557 if (auto colonPos = it.find(":"); colonPos != it.npos) {
558 node.first = it.substr(0, colonPos);
559 node.second = it.substr(colonPos + 1, node.second.npos);
560 } else {
561 node.first = boost::none;
562 node.second = it;
563 }
564
Václav Kubernát72749c62020-01-03 16:47:34 +0100565 if (schema.isLeaf(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.isContainer(parserContext.currentSchemaPath(), node)) {
Václav Kubernáte69133a2019-11-01 19:01:34 +0100569 return it + "/";
570 }
Václav Kubernát72749c62020-01-03 16:47:34 +0100571 if (schema.isList(parserContext.currentSchemaPath(), node)) {
Václav Kubernáte69133a2019-11-01 19:01:34 +0100572 return it + "[";
573 }
574 return it;
575 });
576 parserContext.m_suggestions = suffixesAdded;
Václav Kubernát4108e0d2018-10-29 13:32:22 +0100577 }
578};
Václav Kubernát329c6c32019-02-06 16:41:53 +0100579
Václav Kubernát43908fb2020-01-02 19:05:51 +0100580std::set<std::string> generateMissingKeyCompletionSet(std::set<std::string> keysNeeded, std::map<std::string, leaf_data_> currentSet);
Václav Kubernát329c6c32019-02-06 16:41:53 +0100581
582struct createKeySuggestions_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
Václav Kubernát72749c62020-01-03 16:47:34 +0100591 const auto& keysNeeded = schema.listKeys(parserContext.currentSchemaPath(), {parserContext.m_curModule, parserContext.m_tmpListName});
Václav Kubernát329c6c32019-02-06 16:41:53 +0100592 parserContext.m_suggestions = generateMissingKeyCompletionSet(keysNeeded, parserContext.m_tmpListKeys);
593 }
594};
595
Václav Kubernát43908fb2020-01-02 19:05:51 +0100596std::string leafDataToCompletion(const leaf_data_& value);
597
598struct createValueSuggestions_class {
599 template <typename T, typename Iterator, typename Context>
600 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
601 {
602 auto& parserContext = x3::get<parser_context_tag>(context);
603 if (!parserContext.m_completing) {
604 return;
605 }
606 const auto& dataQuery = parserContext.m_dataquery;
607
608 parserContext.m_completionIterator = begin;
609 auto listInstances = dataQuery->listKeys(parserContext.currentDataPath(), {parserContext.m_curModule, parserContext.m_tmpListName});
610
611 decltype(listInstances) filteredInstances;
612 //This filters out instances, which don't correspond to the partial instance we have.
613 const auto partialFitsComplete = [&parserContext] (const auto& complete) {
614 const auto& partial = parserContext.m_tmpListKeys;
615 return std::all_of(partial.begin(), partial.end(), [&complete] (const auto& oneKV) {
616 const auto& [k, v] = oneKV;
617 return complete.at(k) == v;
618 });
619 };
620 std::copy_if(listInstances.begin(), listInstances.end(), std::inserter(filteredInstances, filteredInstances.end()), partialFitsComplete);
621
622 std::set<std::string> validValues;
623
624 std::transform(filteredInstances.begin(), filteredInstances.end(), std::inserter(validValues, validValues.end()), [&parserContext] (const auto& instance) {
625 return leafDataToCompletion(instance.at(parserContext.m_tmpListKeyLeafPath.m_node.second));
626 });
627
628 parserContext.m_suggestions = validValues;
629 }
630};
631
Václav Kubernát329c6c32019-02-06 16:41:53 +0100632struct suggestKeysEnd_class {
633 template <typename T, typename Iterator, typename Context>
634 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
635 {
636 auto& parserContext = x3::get<parser_context_tag>(context);
637 const auto& schema = parserContext.m_schema;
638
639 parserContext.m_completionIterator = begin;
Václav Kubernát72749c62020-01-03 16:47:34 +0100640 const auto& keysNeeded = schema.listKeys(parserContext.currentSchemaPath(), {parserContext.m_curModule, parserContext.m_tmpListName});
Václav Kubernát329c6c32019-02-06 16:41:53 +0100641 if (generateMissingKeyCompletionSet(keysNeeded, parserContext.m_tmpListKeys).empty()) {
642 parserContext.m_suggestions = {"]/"};
643 } else {
Václav Kubernát4c325482019-04-11 17:51:55 +0200644 parserContext.m_suggestions = {"]["};
Václav Kubernát329c6c32019-02-06 16:41:53 +0100645 }
646 }
647};
Václav Kubernát57272422019-02-08 12:48:24 +0100648
649struct commandNamesVisitor {
650 template <typename T>
651 auto operator()(boost::type<T>)
652 {
653 return T::name;
654 }
655};
656
657struct createCommandSuggestions_class {
658 template <typename T, typename Iterator, typename Context>
659 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
660 {
661 auto& parserContext = x3::get<parser_context_tag>(context);
662 parserContext.m_completionIterator = begin;
663
664 parserContext.m_suggestions.clear();
665 boost::mpl::for_each<CommandTypes, boost::type<boost::mpl::_>>([&parserContext](auto cmd) {
666 parserContext.m_suggestions.emplace(commandNamesVisitor()(cmd));
667 });
668 }
669};
Václav Kubernátac035d62019-02-18 10:59:08 +0100670
671struct completing_class {
672 template <typename T, typename Iterator, typename Context>
673 void on_success(Iterator const&, Iterator const&, T&, Context const& context)
674 {
675 auto& parserContext = x3::get<parser_context_tag>(context);
676
677 if (!parserContext.m_completing)
678 _pass(context) = false;
679 }
680};
Václav Kubernát989b5de2019-02-20 16:28:35 +0100681
682struct createEnumSuggestions_class {
683 template <typename T, typename Iterator, typename Context>
684 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
685 {
686 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernát989b5de2019-02-20 16:28:35 +0100687 const Schema& schema = parserContext.m_schema;
688
Václav Kubernáteeb38842019-03-20 19:46:05 +0100689 // Only generate completions if the type is enum so that we don't
690 // overwrite some other completions.
Václav Kubernát117f7b52020-01-23 16:10:55 +0100691 if (schema.leafType(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node) == yang::LeafDataTypes::Enum) {
692 parserContext.m_completionIterator = begin;
Václav Kubernát7707cae2020-01-16 12:04:53 +0100693 parserContext.m_suggestions = schema.enumValues(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node);
Václav Kubernát117f7b52020-01-23 16:10:55 +0100694 }
Václav Kubernáteeb38842019-03-20 19:46:05 +0100695 }
696};
697
698// FIXME: can I reuse createEnumSuggestions?
699struct createIdentitySuggestions_class {
700 template <typename T, typename Iterator, typename Context>
701 void on_success(Iterator const& begin, Iterator const&, T&, Context const& context)
702 {
703 auto& parserContext = x3::get<parser_context_tag>(context);
Václav Kubernáteeb38842019-03-20 19:46:05 +0100704 const Schema& schema = parserContext.m_schema;
705
Václav Kubernáteeb38842019-03-20 19:46:05 +0100706 // Only generate completions if the type is identityref so that we
707 // don't overwrite some other completions.
Václav Kubernát117f7b52020-01-23 16:10:55 +0100708 if (schema.leafType(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node) == yang::LeafDataTypes::IdentityRef) {
709 parserContext.m_completionIterator = begin;
Václav Kubernát7707cae2020-01-16 12:04:53 +0100710 parserContext.m_suggestions = schema.validIdentities(parserContext.m_tmpListKeyLeafPath.m_location, parserContext.m_tmpListKeyLeafPath.m_node, Prefixes::WhenNeeded);
Václav Kubernát117f7b52020-01-23 16:10:55 +0100711 }
Václav Kubernát989b5de2019-02-20 16:28:35 +0100712 }
713};