blob: 33b25fe9f2e2e6d8a8496be11322ecd8e2c43719 [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{
Václav Kubernát2db124c2020-05-28 21:58:36 +020066}
67
Václav Kubernát5c75b252018-10-10 18:33:47 +020068schemaNode_::schemaNode_(decltype(m_suffix) node)
69 : m_suffix(node)
70{
71}
72
Václav Kubernát2eaceb82018-10-08 19:56:30 +020073schemaNode_::schemaNode_(module_ module, decltype(m_suffix) node)
74 : m_prefix(module)
75 , m_suffix(node)
76{
77}
Václav Kubernát744f57f2018-06-29 22:46:26 +020078
Václav Kubernát2eaceb82018-10-08 19:56:30 +020079schemaNode_::schemaNode_() = default;
80
81bool schemaNode_::operator==(const schemaNode_& b) const
82{
83 return this->m_suffix == b.m_suffix && this->m_prefix == b.m_prefix;
84}
85
86bool dataNode_::operator==(const dataNode_& b) const
Václav Kubernát744f57f2018-06-29 22:46:26 +020087{
88 return this->m_suffix == b.m_suffix && this->m_prefix == b.m_prefix;
89}
90
Václav Kubernát24df80e2018-06-06 15:18:03 +020091bool leaf_::operator==(const leaf_& b) const
92{
93 return this->m_name == b.m_name;
94}
95
Václav Kubernátc15fe822020-06-04 11:28:39 +020096listElement_::listElement_(const std::string& listName, const ListInstance& keys)
Václav Kubernát24df80e2018-06-06 15:18:03 +020097 : m_name(listName)
98 , m_keys(keys)
99{
100}
101
102bool listElement_::operator==(const listElement_& b) const
103{
104 return (this->m_name == b.m_name && this->m_keys == b.m_keys);
105}
106
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200107bool list_::operator==(const list_& b) const
108{
109 return (this->m_name == b.m_name);
110}
111
Václav Kubernáte7248b22020-06-26 15:38:59 +0200112bool rpcNode_::operator==(const rpcNode_& other) const
113{
114 return this->m_name == other.m_name;
115}
116
Václav Kubernátaa4250a2020-07-22 00:02:23 +0200117bool actionNode_::operator==(const actionNode_& other) const
118{
119 return this->m_name == other.m_name;
120}
121
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200122list_::list_(const std::string& listName)
123 : m_name(listName)
124{
125}
126
Jan Kundrát97376f72020-06-15 19:26:31 +0200127namespace {
128template <typename T, typename U>
129auto findFirstOf(const std::vector<U>& nodes)
130{
131 return std::find_if(nodes.begin(), nodes.end(), [](const auto& e) {
132 return std::holds_alternative<T>(e.m_suffix);
133 });
134}
135
136template <typename T>
137void validatePathNodes(const std::vector<T>& nodes)
138{
139 static_assert(std::is_same<T, dataNode_>() || std::is_same<T, schemaNode_>());
140
141 if (nodes.empty()) {
142 // there are default ctors, so it makes sense to specify the same thing via explicit args and not fail
143 return;
144 }
145
146 if (auto firstLeaf = findFirstOf<leaf_>(nodes);
147 firstLeaf != nodes.end() && firstLeaf != nodes.end() - 1) {
148 throw std::logic_error{"Cannot put any extra nodes after a leaf"};
149 }
150
151 if (auto firstLeafList = findFirstOf<leafList_>(nodes);
152 firstLeafList != nodes.end() && firstLeafList != nodes.end() - 1) {
153 throw std::logic_error{"Cannot put any extra nodes after a leaf-list"};
154 }
155
156 if constexpr (std::is_same<T, dataNode_>()) {
157 if (auto firstLeafListElements = findFirstOf<leafListElement_>(nodes);
158 firstLeafListElements != nodes.end() && firstLeafListElements != nodes.end() - 1) {
159 throw std::logic_error{"Cannot put any extra nodes after a leaf-list with element specification"};
160 }
161 if (auto firstList = findFirstOf<list_>(nodes);
162 firstList != nodes.end() && firstList != nodes.end() - 1) {
163 throw std::logic_error{
164 "A list with no key specification can be present only as a last item in a dataPath. Did you mean to use a schemaPath?"
165 };
166 }
167 }
168}
169}
170
Václav Kubernát51fa48e2020-07-08 17:17:34 +0200171schemaPath_::schemaPath_() = default;
Jan Kundrát97376f72020-06-15 19:26:31 +0200172
Václav Kubernát39f83f52021-02-19 02:52:08 +0100173schemaPath_::schemaPath_(const Scope scope, const std::vector<schemaNode_>& nodes)
Jan Kundrát97376f72020-06-15 19:26:31 +0200174 : m_scope(scope)
175 , m_nodes(nodes)
Jan Kundrát97376f72020-06-15 19:26:31 +0200176{
177 validatePathNodes(m_nodes);
178}
179
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200180bool schemaPath_::operator==(const schemaPath_& b) const
181{
Václav Kubernát3a433232020-07-08 17:52:50 +0200182 if (this->m_nodes.size() != b.m_nodes.size()) {
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200183 return false;
Václav Kubernát3a433232020-07-08 17:52:50 +0200184 }
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200185 return this->m_nodes == b.m_nodes;
186}
187
Václav Kubernát51fa48e2020-07-08 17:17:34 +0200188dataPath_::dataPath_() = default;
Jan Kundrát97376f72020-06-15 19:26:31 +0200189
Václav Kubernát39f83f52021-02-19 02:52:08 +0100190dataPath_::dataPath_(const Scope scope, const std::vector<dataNode_>& nodes)
Jan Kundrát97376f72020-06-15 19:26:31 +0200191 : m_scope(scope)
192 , m_nodes(nodes)
Jan Kundrát97376f72020-06-15 19:26:31 +0200193{
194 validatePathNodes(m_nodes);
195}
196
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200197bool dataPath_::operator==(const dataPath_& b) const
Václav Kubernát24df80e2018-06-06 15:18:03 +0200198{
Václav Kubernát3a433232020-07-08 17:52:50 +0200199 if (this->m_nodes.size() != b.m_nodes.size()) {
Václav Kubernát24df80e2018-06-06 15:18:03 +0200200 return false;
Václav Kubernát3a433232020-07-08 17:52:50 +0200201 }
Václav Kubernát24df80e2018-06-06 15:18:03 +0200202 return this->m_nodes == b.m_nodes;
203}
204
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200205struct nodeToSchemaStringVisitor {
Václav Kubernát24df80e2018-06-06 15:18:03 +0200206 std::string operator()(const nodeup_&) const
207 {
208 return "..";
209 }
210 template <class T>
211 std::string operator()(const T& node) const
212 {
213 return node.m_name;
214 }
215};
Jan Kundrát2a8f4332018-09-14 17:05:31 +0200216
217std::string escapeListKeyString(const std::string& what)
218{
219 // If we have both single and double quote, then we're screwed, but that "shouldn't happen"
220 // in <= YANG 1.1 due to limitations in XPath 1.0.
221 if (what.find('\'') != std::string::npos) {
222 return '\"' + what + '\"';
223 } else {
224 return '\'' + what + '\'';
225 }
226}
227
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200228struct nodeToDataStringVisitor {
Václav Kubernát24df80e2018-06-06 15:18:03 +0200229 std::string operator()(const listElement_& node) const
230 {
231 std::ostringstream res;
232 res << node.m_name + "[";
233 std::transform(node.m_keys.begin(), node.m_keys.end(),
Václav Kubernát5395e712019-12-03 18:24:33 +0100234 std::experimental::make_ostream_joiner(res, "]["),
Václav Kubernát7707cae2020-01-16 12:04:53 +0100235 [] (const auto& it) { return it.first + "=" + escapeListKeyString(leafDataToString(it.second)); });
Václav Kubernát24df80e2018-06-06 15:18:03 +0200236 res << "]";
Václav Kubernátebca2552018-06-08 19:06:02 +0200237 return res.str();
Václav Kubernát24df80e2018-06-06 15:18:03 +0200238 }
Václav Kubernát5b8a8f32020-05-20 00:57:22 +0200239 std::string operator()(const leafListElement_& node) const
240 {
241 return node.m_name + "[.=" + escapeListKeyString(leafDataToString(node.m_value)) + "]";
242 }
Václav Kubernát24df80e2018-06-06 15:18:03 +0200243 std::string operator()(const nodeup_&) const
244 {
245 return "..";
246 }
247 template <class T>
248 std::string operator()(const T& node) const
249 {
250 return node.m_name;
251 }
252};
253
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200254std::string nodeToSchemaString(decltype(dataPath_::m_nodes)::value_type node)
Václav Kubernát744f57f2018-06-29 22:46:26 +0200255{
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200256 return std::visit(nodeToSchemaStringVisitor(), node.m_suffix);
Václav Kubernát744f57f2018-06-29 22:46:26 +0200257}
258
Václav Kubernátefcac932020-01-10 15:26:32 +0100259std::string pathToDataString(const dataPath_& path, Prefixes prefixes)
Václav Kubernát24df80e2018-06-06 15:18:03 +0200260{
261 std::string res;
Václav Kubernát5395e712019-12-03 18:24:33 +0100262 if (path.m_scope == Scope::Absolute) {
263 res = "/";
264 }
Václav Kubernátefcac932020-01-10 15:26:32 +0100265
Václav Kubernátef085742020-04-21 09:28:44 +0200266 for (const auto& it : path.m_nodes) {
Václav Kubernát3a433232020-07-08 17:52:50 +0200267 if (it.m_prefix) {
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200268 res = joinPaths(res, it.m_prefix.value().m_name + ":" + std::visit(nodeToDataStringVisitor(), it.m_suffix));
Václav Kubernát3a433232020-07-08 17:52:50 +0200269 } else {
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200270 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 +0200271 }
Václav Kubernátefcac932020-01-10 15:26:32 +0100272 }
Václav Kubernát744f57f2018-06-29 22:46:26 +0200273
274 return res;
275}
276
Václav Kubernátefcac932020-01-10 15:26:32 +0100277std::string pathToSchemaString(const schemaPath_& path, Prefixes prefixes)
Václav Kubernát744f57f2018-06-29 22:46:26 +0200278{
279 std::string res;
Václav Kubernátefcac932020-01-10 15:26:32 +0100280 if (path.m_scope == Scope::Absolute) {
281 res = "/";
Václav Kubernát744f57f2018-06-29 22:46:26 +0200282 }
283
Václav Kubernátef085742020-04-21 09:28:44 +0200284 for (const auto& it : path.m_nodes) {
Václav Kubernát3a433232020-07-08 17:52:50 +0200285 if (it.m_prefix) {
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200286 res = joinPaths(res, it.m_prefix.value().m_name + ":" + std::visit(nodeToSchemaStringVisitor(), it.m_suffix));
Václav Kubernát3a433232020-07-08 17:52:50 +0200287 } else {
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200288 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 +0200289 }
Václav Kubernát744f57f2018-06-29 22:46:26 +0200290 }
Václav Kubernát24df80e2018-06-06 15:18:03 +0200291 return res;
292}
293
Václav Kubernátefcac932020-01-10 15:26:32 +0100294std::string pathToSchemaString(const dataPath_& path, Prefixes prefixes)
Václav Kubernát24df80e2018-06-06 15:18:03 +0200295{
Václav Kubernátefcac932020-01-10 15:26:32 +0100296 return pathToSchemaString(dataPathToSchemaPath(path), prefixes);
Václav Kubernát5c75b252018-10-10 18:33:47 +0200297}
298
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200299struct dataSuffixToSchemaSuffix {
300 using ReturnType = decltype(schemaNode_::m_suffix);
301 ReturnType operator()(const listElement_& listElement) const
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200302 {
303 return list_{listElement.m_name};
304 }
305
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200306 ReturnType operator()(const leafListElement_& leafListElement) const
Václav Kubernát5b8a8f32020-05-20 00:57:22 +0200307 {
308 return leafList_{leafListElement.m_name};
309 }
310
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200311 template <typename T>
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200312 ReturnType operator()(const T& suffix) const
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200313 {
314 return suffix;
315 }
316};
317
318schemaNode_ dataNodeToSchemaNode(const dataNode_& node)
319{
320 schemaNode_ res;
321 res.m_prefix = node.m_prefix;
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200322 res.m_suffix = std::visit(dataSuffixToSchemaSuffix(), node.m_suffix);
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200323 return res;
324}
325
326schemaPath_ dataPathToSchemaPath(const dataPath_& path)
327{
Václav Kubernátbf083ec2019-02-19 13:58:09 +0100328 schemaPath_ res{path.m_scope, {}};
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200329
Václav Kubernátbf083ec2019-02-19 13:58:09 +0100330 std::transform(path.m_nodes.begin(), path.m_nodes.end(),
331 std::back_inserter(res.m_nodes),
332 [](const dataNode_& node) { return dataNodeToSchemaNode(node); });
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200333
Václav Kubernátbf083ec2019-02-19 13:58:09 +0100334 return res;
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200335}
Václav Kubernáte781b902020-06-15 14:35:11 +0200336
337namespace {
338template <typename NodeType>
339void impl_pushFragment(std::vector<NodeType>& where, const NodeType& what)
340{
341 if (std::holds_alternative<nodeup_>(what.m_suffix)) {
342 if (!where.empty()) { // Allow going up, when already at root
343 where.pop_back();
344 }
345 } else {
Václav Kubernátfaacd022020-07-08 16:44:38 +0200346 where.emplace_back(what);
Václav Kubernáte781b902020-06-15 14:35:11 +0200347 }
348}
349}
350
351void schemaPath_::pushFragment(const schemaNode_& fragment)
352{
353 impl_pushFragment(m_nodes, fragment);
Jan Kundrát97376f72020-06-15 19:26:31 +0200354 validatePathNodes(m_nodes);
Václav Kubernáte781b902020-06-15 14:35:11 +0200355}
356
357void dataPath_::pushFragment(const dataNode_& fragment)
358{
359 impl_pushFragment(m_nodes, fragment);
Jan Kundrát97376f72020-06-15 19:26:31 +0200360 validatePathNodes(m_nodes);
Václav Kubernáte781b902020-06-15 14:35:11 +0200361}