blob: b9f7ae492fc92b67d44a0d3fbbd701f975525399 [file] [log] [blame]
Václav Kubernát24df80e2018-06-06 15:18:03 +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#include <experimental/iterator>
Václav Kubernát509ce652019-05-29 19:46:44 +020010#include <sstream>
Václav Kubernát24df80e2018-06-06 15:18:03 +020011#include "ast_path.hpp"
12#include "utils.hpp"
13
14container_::container_(const std::string& name)
15 : m_name(name)
16{
17}
18
19bool container_::operator==(const container_& b) const
20{
21 return this->m_name == b.m_name;
22}
23
24leaf_::leaf_(const std::string& name)
25 : m_name(name)
26{
27}
28
Václav Kubernát5b8a8f32020-05-20 00:57:22 +020029bool leafListElement_::operator==(const leafListElement_& b) const
30{
31 return this->m_name == b.m_name && this->m_value == b.m_value;
32}
33
Václav Kubernát5b8a8f32020-05-20 00:57:22 +020034leafList_::leafList_(const std::string& name)
35 : m_name(name)
36{
37}
38
39bool leafList_::operator==(const leafList_& b) const
40{
41 return this->m_name == b.m_name;
42}
43
Václav Kubernát744f57f2018-06-29 22:46:26 +020044bool module_::operator==(const module_& b) const
45{
46 return this->m_name == b.m_name;
47}
48
Václav Kubernát2eaceb82018-10-08 19:56:30 +020049dataNode_::dataNode_() = default;
Václav Kubernát744f57f2018-06-29 22:46:26 +020050
Václav Kubernát2eaceb82018-10-08 19:56:30 +020051dataNode_::dataNode_(decltype(m_suffix) node)
Václav Kubernát744f57f2018-06-29 22:46:26 +020052 : m_suffix(node)
53{
54}
55
Václav Kubernát2eaceb82018-10-08 19:56:30 +020056dataNode_::dataNode_(module_ module, decltype(m_suffix) node)
Václav Kubernát744f57f2018-06-29 22:46:26 +020057 : m_prefix(module)
58 , m_suffix(node)
59{
60}
61
Václav Kubernát2db124c2020-05-28 21:58:36 +020062dataNode_::dataNode_(boost::optional<module_> module, decltype(m_suffix) node)
63 : m_prefix(module)
64 , m_suffix(node)
65{
66
67}
68
Václav Kubernát5c75b252018-10-10 18:33:47 +020069schemaNode_::schemaNode_(decltype(m_suffix) node)
70 : m_suffix(node)
71{
72}
73
Václav Kubernát2eaceb82018-10-08 19:56:30 +020074schemaNode_::schemaNode_(module_ module, decltype(m_suffix) node)
75 : m_prefix(module)
76 , m_suffix(node)
77{
78}
Václav Kubernát744f57f2018-06-29 22:46:26 +020079
Václav Kubernát2eaceb82018-10-08 19:56:30 +020080schemaNode_::schemaNode_() = default;
81
82bool schemaNode_::operator==(const schemaNode_& b) const
83{
84 return this->m_suffix == b.m_suffix && this->m_prefix == b.m_prefix;
85}
86
87bool dataNode_::operator==(const dataNode_& b) const
Václav Kubernát744f57f2018-06-29 22:46:26 +020088{
89 return this->m_suffix == b.m_suffix && this->m_prefix == b.m_prefix;
90}
91
Václav Kubernát24df80e2018-06-06 15:18:03 +020092bool leaf_::operator==(const leaf_& b) const
93{
94 return this->m_name == b.m_name;
95}
96
Václav Kubernátc15fe822020-06-04 11:28:39 +020097listElement_::listElement_(const std::string& listName, const ListInstance& keys)
Václav Kubernát24df80e2018-06-06 15:18:03 +020098 : m_name(listName)
99 , m_keys(keys)
100{
101}
102
103bool listElement_::operator==(const listElement_& b) const
104{
105 return (this->m_name == b.m_name && this->m_keys == b.m_keys);
106}
107
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200108bool list_::operator==(const list_& b) const
109{
110 return (this->m_name == b.m_name);
111}
112
Václav Kubernáte7248b22020-06-26 15:38:59 +0200113bool rpcNode_::operator==(const rpcNode_& other) const
114{
115 return this->m_name == other.m_name;
116}
117
Václav Kubernátaa4250a2020-07-22 00:02:23 +0200118bool actionNode_::operator==(const actionNode_& other) const
119{
120 return this->m_name == other.m_name;
121}
122
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200123list_::list_(const std::string& listName)
124 : m_name(listName)
125{
126}
127
Jan Kundrát97376f72020-06-15 19:26:31 +0200128namespace {
129template <typename T, typename U>
130auto findFirstOf(const std::vector<U>& nodes)
131{
132 return std::find_if(nodes.begin(), nodes.end(), [](const auto& e) {
133 return std::holds_alternative<T>(e.m_suffix);
134 });
135}
136
137template <typename T>
138void validatePathNodes(const std::vector<T>& nodes)
139{
140 static_assert(std::is_same<T, dataNode_>() || std::is_same<T, schemaNode_>());
141
142 if (nodes.empty()) {
143 // there are default ctors, so it makes sense to specify the same thing via explicit args and not fail
144 return;
145 }
146
147 if (auto firstLeaf = findFirstOf<leaf_>(nodes);
148 firstLeaf != nodes.end() && firstLeaf != nodes.end() - 1) {
149 throw std::logic_error{"Cannot put any extra nodes after a leaf"};
150 }
151
152 if (auto firstLeafList = findFirstOf<leafList_>(nodes);
153 firstLeafList != nodes.end() && firstLeafList != nodes.end() - 1) {
154 throw std::logic_error{"Cannot put any extra nodes after a leaf-list"};
155 }
156
157 if constexpr (std::is_same<T, dataNode_>()) {
158 if (auto firstLeafListElements = findFirstOf<leafListElement_>(nodes);
159 firstLeafListElements != nodes.end() && firstLeafListElements != nodes.end() - 1) {
160 throw std::logic_error{"Cannot put any extra nodes after a leaf-list with element specification"};
161 }
162 if (auto firstList = findFirstOf<list_>(nodes);
163 firstList != nodes.end() && firstList != nodes.end() - 1) {
164 throw std::logic_error{
165 "A list with no key specification can be present only as a last item in a dataPath. Did you mean to use a schemaPath?"
166 };
167 }
168 }
169}
170}
171
Václav Kubernát51fa48e2020-07-08 17:17:34 +0200172schemaPath_::schemaPath_() = default;
Jan Kundrát97376f72020-06-15 19:26:31 +0200173
174schemaPath_::schemaPath_(const Scope scope, const std::vector<schemaNode_>& nodes, const TrailingSlash trailingSlash)
175 : m_scope(scope)
176 , m_nodes(nodes)
177 , m_trailingSlash(trailingSlash)
178{
179 validatePathNodes(m_nodes);
180}
181
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200182bool schemaPath_::operator==(const schemaPath_& b) const
183{
Václav Kubernát3a433232020-07-08 17:52:50 +0200184 if (this->m_nodes.size() != b.m_nodes.size()) {
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200185 return false;
Václav Kubernát3a433232020-07-08 17:52:50 +0200186 }
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200187 return this->m_nodes == b.m_nodes;
188}
189
Václav Kubernát51fa48e2020-07-08 17:17:34 +0200190dataPath_::dataPath_() = default;
Jan Kundrát97376f72020-06-15 19:26:31 +0200191
192dataPath_::dataPath_(const Scope scope, const std::vector<dataNode_>& nodes, const TrailingSlash trailingSlash)
193 : m_scope(scope)
194 , m_nodes(nodes)
195 , m_trailingSlash(trailingSlash)
196{
197 validatePathNodes(m_nodes);
198}
199
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200200bool dataPath_::operator==(const dataPath_& b) const
Václav Kubernát24df80e2018-06-06 15:18:03 +0200201{
Václav Kubernát3a433232020-07-08 17:52:50 +0200202 if (this->m_nodes.size() != b.m_nodes.size()) {
Václav Kubernát24df80e2018-06-06 15:18:03 +0200203 return false;
Václav Kubernát3a433232020-07-08 17:52:50 +0200204 }
Václav Kubernát24df80e2018-06-06 15:18:03 +0200205 return this->m_nodes == b.m_nodes;
206}
207
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200208struct nodeToSchemaStringVisitor {
Václav Kubernát24df80e2018-06-06 15:18:03 +0200209 std::string operator()(const nodeup_&) const
210 {
211 return "..";
212 }
213 template <class T>
214 std::string operator()(const T& node) const
215 {
216 return node.m_name;
217 }
218};
Jan Kundrát2a8f4332018-09-14 17:05:31 +0200219
220std::string escapeListKeyString(const std::string& what)
221{
222 // If we have both single and double quote, then we're screwed, but that "shouldn't happen"
223 // in <= YANG 1.1 due to limitations in XPath 1.0.
224 if (what.find('\'') != std::string::npos) {
225 return '\"' + what + '\"';
226 } else {
227 return '\'' + what + '\'';
228 }
229}
230
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200231struct nodeToDataStringVisitor {
Václav Kubernát24df80e2018-06-06 15:18:03 +0200232 std::string operator()(const listElement_& node) const
233 {
234 std::ostringstream res;
235 res << node.m_name + "[";
236 std::transform(node.m_keys.begin(), node.m_keys.end(),
Václav Kubernát5395e712019-12-03 18:24:33 +0100237 std::experimental::make_ostream_joiner(res, "]["),
Václav Kubernát7707cae2020-01-16 12:04:53 +0100238 [] (const auto& it) { return it.first + "=" + escapeListKeyString(leafDataToString(it.second)); });
Václav Kubernát24df80e2018-06-06 15:18:03 +0200239 res << "]";
Václav Kubernátebca2552018-06-08 19:06:02 +0200240 return res.str();
Václav Kubernát24df80e2018-06-06 15:18:03 +0200241 }
Václav Kubernát5b8a8f32020-05-20 00:57:22 +0200242 std::string operator()(const leafListElement_& node) const
243 {
244 return node.m_name + "[.=" + escapeListKeyString(leafDataToString(node.m_value)) + "]";
245 }
Václav Kubernát24df80e2018-06-06 15:18:03 +0200246 std::string operator()(const nodeup_&) const
247 {
248 return "..";
249 }
250 template <class T>
251 std::string operator()(const T& node) const
252 {
253 return node.m_name;
254 }
255};
256
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200257std::string nodeToSchemaString(decltype(dataPath_::m_nodes)::value_type node)
Václav Kubernát744f57f2018-06-29 22:46:26 +0200258{
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200259 return std::visit(nodeToSchemaStringVisitor(), node.m_suffix);
Václav Kubernát744f57f2018-06-29 22:46:26 +0200260}
261
Václav Kubernátefcac932020-01-10 15:26:32 +0100262std::string pathToDataString(const dataPath_& path, Prefixes prefixes)
Václav Kubernát24df80e2018-06-06 15:18:03 +0200263{
264 std::string res;
Václav Kubernát5395e712019-12-03 18:24:33 +0100265 if (path.m_scope == Scope::Absolute) {
266 res = "/";
267 }
Václav Kubernátefcac932020-01-10 15:26:32 +0100268
Václav Kubernátef085742020-04-21 09:28:44 +0200269 for (const auto& it : path.m_nodes) {
Václav Kubernát3a433232020-07-08 17:52:50 +0200270 if (it.m_prefix) {
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200271 res = joinPaths(res, it.m_prefix.value().m_name + ":" + std::visit(nodeToDataStringVisitor(), it.m_suffix));
Václav Kubernát3a433232020-07-08 17:52:50 +0200272 } else {
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200273 res = joinPaths(res, (prefixes == Prefixes::Always ? path.m_nodes.at(0).m_prefix.value().m_name + ":" : "") + std::visit(nodeToDataStringVisitor(), it.m_suffix));
Václav Kubernát3a433232020-07-08 17:52:50 +0200274 }
Václav Kubernátefcac932020-01-10 15:26:32 +0100275 }
Václav Kubernát744f57f2018-06-29 22:46:26 +0200276
277 return res;
278}
279
Václav Kubernátefcac932020-01-10 15:26:32 +0100280std::string pathToSchemaString(const schemaPath_& path, Prefixes prefixes)
Václav Kubernát744f57f2018-06-29 22:46:26 +0200281{
282 std::string res;
Václav Kubernátefcac932020-01-10 15:26:32 +0100283 if (path.m_scope == Scope::Absolute) {
284 res = "/";
Václav Kubernát744f57f2018-06-29 22:46:26 +0200285 }
286
Václav Kubernátef085742020-04-21 09:28:44 +0200287 for (const auto& it : path.m_nodes) {
Václav Kubernát3a433232020-07-08 17:52:50 +0200288 if (it.m_prefix) {
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200289 res = joinPaths(res, it.m_prefix.value().m_name + ":" + std::visit(nodeToSchemaStringVisitor(), it.m_suffix));
Václav Kubernát3a433232020-07-08 17:52:50 +0200290 } else {
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200291 res = joinPaths(res, (prefixes == Prefixes::Always ? path.m_nodes.at(0).m_prefix.value().m_name + ":" : "") + std::visit(nodeToSchemaStringVisitor(), it.m_suffix));
Václav Kubernát3a433232020-07-08 17:52:50 +0200292 }
Václav Kubernát744f57f2018-06-29 22:46:26 +0200293 }
Václav Kubernát24df80e2018-06-06 15:18:03 +0200294 return res;
295}
296
Václav Kubernátefcac932020-01-10 15:26:32 +0100297std::string pathToSchemaString(const dataPath_& path, Prefixes prefixes)
Václav Kubernát24df80e2018-06-06 15:18:03 +0200298{
Václav Kubernátefcac932020-01-10 15:26:32 +0100299 return pathToSchemaString(dataPathToSchemaPath(path), prefixes);
Václav Kubernát5c75b252018-10-10 18:33:47 +0200300}
301
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200302struct dataSuffixToSchemaSuffix {
303 using ReturnType = decltype(schemaNode_::m_suffix);
304 ReturnType operator()(const listElement_& listElement) const
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200305 {
306 return list_{listElement.m_name};
307 }
308
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200309 ReturnType operator()(const leafListElement_& leafListElement) const
Václav Kubernát5b8a8f32020-05-20 00:57:22 +0200310 {
311 return leafList_{leafListElement.m_name};
312 }
313
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200314 template <typename T>
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200315 ReturnType operator()(const T& suffix) const
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200316 {
317 return suffix;
318 }
319};
320
321schemaNode_ dataNodeToSchemaNode(const dataNode_& node)
322{
323 schemaNode_ res;
324 res.m_prefix = node.m_prefix;
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200325 res.m_suffix = std::visit(dataSuffixToSchemaSuffix(), node.m_suffix);
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200326 return res;
327}
328
329schemaPath_ dataPathToSchemaPath(const dataPath_& path)
330{
Václav Kubernátbf083ec2019-02-19 13:58:09 +0100331 schemaPath_ res{path.m_scope, {}};
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200332
Václav Kubernátbf083ec2019-02-19 13:58:09 +0100333 std::transform(path.m_nodes.begin(), path.m_nodes.end(),
334 std::back_inserter(res.m_nodes),
335 [](const dataNode_& node) { return dataNodeToSchemaNode(node); });
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200336
Václav Kubernátbf083ec2019-02-19 13:58:09 +0100337 return res;
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200338}
Václav Kubernáte781b902020-06-15 14:35:11 +0200339
340namespace {
341template <typename NodeType>
342void impl_pushFragment(std::vector<NodeType>& where, const NodeType& what)
343{
344 if (std::holds_alternative<nodeup_>(what.m_suffix)) {
345 if (!where.empty()) { // Allow going up, when already at root
346 where.pop_back();
347 }
348 } else {
Václav Kubernátfaacd022020-07-08 16:44:38 +0200349 where.emplace_back(what);
Václav Kubernáte781b902020-06-15 14:35:11 +0200350 }
351}
352}
353
354void schemaPath_::pushFragment(const schemaNode_& fragment)
355{
356 impl_pushFragment(m_nodes, fragment);
Jan Kundrát97376f72020-06-15 19:26:31 +0200357 validatePathNodes(m_nodes);
Václav Kubernáte781b902020-06-15 14:35:11 +0200358}
359
360void dataPath_::pushFragment(const dataNode_& fragment)
361{
362 impl_pushFragment(m_nodes, fragment);
Jan Kundrát97376f72020-06-15 19:26:31 +0200363 validatePathNodes(m_nodes);
Václav Kubernáte781b902020-06-15 14:35:11 +0200364}