blob: 9c77f351e931cc23b3e6a834cba210ec2739c5ba [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
173schemaPath_::schemaPath_(const Scope scope, const std::vector<schemaNode_>& nodes, const TrailingSlash trailingSlash)
174 : m_scope(scope)
175 , m_nodes(nodes)
176 , m_trailingSlash(trailingSlash)
177{
178 validatePathNodes(m_nodes);
179}
180
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200181bool schemaPath_::operator==(const schemaPath_& b) const
182{
Václav Kubernát3a433232020-07-08 17:52:50 +0200183 if (this->m_nodes.size() != b.m_nodes.size()) {
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200184 return false;
Václav Kubernát3a433232020-07-08 17:52:50 +0200185 }
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200186 return this->m_nodes == b.m_nodes;
187}
188
Václav Kubernát51fa48e2020-07-08 17:17:34 +0200189dataPath_::dataPath_() = default;
Jan Kundrát97376f72020-06-15 19:26:31 +0200190
191dataPath_::dataPath_(const Scope scope, const std::vector<dataNode_>& nodes, const TrailingSlash trailingSlash)
192 : m_scope(scope)
193 , m_nodes(nodes)
194 , m_trailingSlash(trailingSlash)
195{
196 validatePathNodes(m_nodes);
197}
198
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200199bool dataPath_::operator==(const dataPath_& b) const
Václav Kubernát24df80e2018-06-06 15:18:03 +0200200{
Václav Kubernát3a433232020-07-08 17:52:50 +0200201 if (this->m_nodes.size() != b.m_nodes.size()) {
Václav Kubernát24df80e2018-06-06 15:18:03 +0200202 return false;
Václav Kubernát3a433232020-07-08 17:52:50 +0200203 }
Václav Kubernát24df80e2018-06-06 15:18:03 +0200204 return this->m_nodes == b.m_nodes;
205}
206
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200207struct nodeToSchemaStringVisitor {
Václav Kubernát24df80e2018-06-06 15:18:03 +0200208 std::string operator()(const nodeup_&) const
209 {
210 return "..";
211 }
212 template <class T>
213 std::string operator()(const T& node) const
214 {
215 return node.m_name;
216 }
217};
Jan Kundrát2a8f4332018-09-14 17:05:31 +0200218
219std::string escapeListKeyString(const std::string& what)
220{
221 // If we have both single and double quote, then we're screwed, but that "shouldn't happen"
222 // in <= YANG 1.1 due to limitations in XPath 1.0.
223 if (what.find('\'') != std::string::npos) {
224 return '\"' + what + '\"';
225 } else {
226 return '\'' + what + '\'';
227 }
228}
229
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200230struct nodeToDataStringVisitor {
Václav Kubernát24df80e2018-06-06 15:18:03 +0200231 std::string operator()(const listElement_& node) const
232 {
233 std::ostringstream res;
234 res << node.m_name + "[";
235 std::transform(node.m_keys.begin(), node.m_keys.end(),
Václav Kubernát5395e712019-12-03 18:24:33 +0100236 std::experimental::make_ostream_joiner(res, "]["),
Václav Kubernát7707cae2020-01-16 12:04:53 +0100237 [] (const auto& it) { return it.first + "=" + escapeListKeyString(leafDataToString(it.second)); });
Václav Kubernát24df80e2018-06-06 15:18:03 +0200238 res << "]";
Václav Kubernátebca2552018-06-08 19:06:02 +0200239 return res.str();
Václav Kubernát24df80e2018-06-06 15:18:03 +0200240 }
Václav Kubernát5b8a8f32020-05-20 00:57:22 +0200241 std::string operator()(const leafListElement_& node) const
242 {
243 return node.m_name + "[.=" + escapeListKeyString(leafDataToString(node.m_value)) + "]";
244 }
Václav Kubernát24df80e2018-06-06 15:18:03 +0200245 std::string operator()(const nodeup_&) const
246 {
247 return "..";
248 }
249 template <class T>
250 std::string operator()(const T& node) const
251 {
252 return node.m_name;
253 }
254};
255
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200256std::string nodeToSchemaString(decltype(dataPath_::m_nodes)::value_type node)
Václav Kubernát744f57f2018-06-29 22:46:26 +0200257{
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200258 return std::visit(nodeToSchemaStringVisitor(), node.m_suffix);
Václav Kubernát744f57f2018-06-29 22:46:26 +0200259}
260
Václav Kubernátefcac932020-01-10 15:26:32 +0100261std::string pathToDataString(const dataPath_& path, Prefixes prefixes)
Václav Kubernát24df80e2018-06-06 15:18:03 +0200262{
263 std::string res;
Václav Kubernát5395e712019-12-03 18:24:33 +0100264 if (path.m_scope == Scope::Absolute) {
265 res = "/";
266 }
Václav Kubernátefcac932020-01-10 15:26:32 +0100267
Václav Kubernátef085742020-04-21 09:28:44 +0200268 for (const auto& it : path.m_nodes) {
Václav Kubernát3a433232020-07-08 17:52:50 +0200269 if (it.m_prefix) {
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200270 res = joinPaths(res, it.m_prefix.value().m_name + ":" + std::visit(nodeToDataStringVisitor(), it.m_suffix));
Václav Kubernát3a433232020-07-08 17:52:50 +0200271 } else {
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200272 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 +0200273 }
Václav Kubernátefcac932020-01-10 15:26:32 +0100274 }
Václav Kubernátce108db2021-01-25 10:05:40 +0100275 if (path.m_trailingSlash == TrailingSlash::Present) {
276 res += "/";
277 }
Václav Kubernát744f57f2018-06-29 22:46:26 +0200278
279 return res;
280}
281
Václav Kubernátefcac932020-01-10 15:26:32 +0100282std::string pathToSchemaString(const schemaPath_& path, Prefixes prefixes)
Václav Kubernát744f57f2018-06-29 22:46:26 +0200283{
284 std::string res;
Václav Kubernátefcac932020-01-10 15:26:32 +0100285 if (path.m_scope == Scope::Absolute) {
286 res = "/";
Václav Kubernát744f57f2018-06-29 22:46:26 +0200287 }
288
Václav Kubernátef085742020-04-21 09:28:44 +0200289 for (const auto& it : path.m_nodes) {
Václav Kubernát3a433232020-07-08 17:52:50 +0200290 if (it.m_prefix) {
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200291 res = joinPaths(res, it.m_prefix.value().m_name + ":" + std::visit(nodeToSchemaStringVisitor(), it.m_suffix));
Václav Kubernát3a433232020-07-08 17:52:50 +0200292 } else {
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200293 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 +0200294 }
Václav Kubernát744f57f2018-06-29 22:46:26 +0200295 }
Václav Kubernát24df80e2018-06-06 15:18:03 +0200296 return res;
297}
298
Václav Kubernátefcac932020-01-10 15:26:32 +0100299std::string pathToSchemaString(const dataPath_& path, Prefixes prefixes)
Václav Kubernát24df80e2018-06-06 15:18:03 +0200300{
Václav Kubernátefcac932020-01-10 15:26:32 +0100301 return pathToSchemaString(dataPathToSchemaPath(path), prefixes);
Václav Kubernát5c75b252018-10-10 18:33:47 +0200302}
303
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200304struct dataSuffixToSchemaSuffix {
305 using ReturnType = decltype(schemaNode_::m_suffix);
306 ReturnType operator()(const listElement_& listElement) const
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200307 {
308 return list_{listElement.m_name};
309 }
310
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200311 ReturnType operator()(const leafListElement_& leafListElement) const
Václav Kubernát5b8a8f32020-05-20 00:57:22 +0200312 {
313 return leafList_{leafListElement.m_name};
314 }
315
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200316 template <typename T>
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200317 ReturnType operator()(const T& suffix) const
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200318 {
319 return suffix;
320 }
321};
322
323schemaNode_ dataNodeToSchemaNode(const dataNode_& node)
324{
325 schemaNode_ res;
326 res.m_prefix = node.m_prefix;
Václav Kubernátb5ca1542020-05-27 01:03:54 +0200327 res.m_suffix = std::visit(dataSuffixToSchemaSuffix(), node.m_suffix);
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200328 return res;
329}
330
331schemaPath_ dataPathToSchemaPath(const dataPath_& path)
332{
Václav Kubernátbf083ec2019-02-19 13:58:09 +0100333 schemaPath_ res{path.m_scope, {}};
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200334
Václav Kubernátbf083ec2019-02-19 13:58:09 +0100335 std::transform(path.m_nodes.begin(), path.m_nodes.end(),
336 std::back_inserter(res.m_nodes),
337 [](const dataNode_& node) { return dataNodeToSchemaNode(node); });
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200338
Václav Kubernátbf083ec2019-02-19 13:58:09 +0100339 return res;
Václav Kubernát2eaceb82018-10-08 19:56:30 +0200340}
Václav Kubernáte781b902020-06-15 14:35:11 +0200341
342namespace {
343template <typename NodeType>
344void impl_pushFragment(std::vector<NodeType>& where, const NodeType& what)
345{
346 if (std::holds_alternative<nodeup_>(what.m_suffix)) {
347 if (!where.empty()) { // Allow going up, when already at root
348 where.pop_back();
349 }
350 } else {
Václav Kubernátfaacd022020-07-08 16:44:38 +0200351 where.emplace_back(what);
Václav Kubernáte781b902020-06-15 14:35:11 +0200352 }
353}
354}
355
356void schemaPath_::pushFragment(const schemaNode_& fragment)
357{
358 impl_pushFragment(m_nodes, fragment);
Jan Kundrát97376f72020-06-15 19:26:31 +0200359 validatePathNodes(m_nodes);
Václav Kubernáte781b902020-06-15 14:35:11 +0200360}
361
362void dataPath_::pushFragment(const dataNode_& fragment)
363{
364 impl_pushFragment(m_nodes, fragment);
Jan Kundrát97376f72020-06-15 19:26:31 +0200365 validatePathNodes(m_nodes);
Václav Kubernáte781b902020-06-15 14:35:11 +0200366}