libs/kdl/src/eu/kdl/kdl.cc
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "eu/kdl/kdl.h" | ||
| 2 | |||
| 3 | #include <cassert> | ||
| 4 | #include <kdl/kdl.h> | ||
| 5 | |||
| 6 | namespace eu::kdl | ||
| 7 | { | ||
| 8 | |||
| 9 | |||
| 10 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 11 | // internal helper functions | ||
| 12 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 13 | |||
| 14 | namespace | ||
| 15 | { | ||
| 16 | ✗ | std::string_view to_u8string_view(kdl_str const& s) | |
| 17 | { | ||
| 18 | ✗ | return std::string_view{reinterpret_cast<char const*>(s.data), s.len}; | |
| 19 | } | ||
| 20 | |||
| 21 | ✗ | kdl_str to_kdl_str(std::string_view s) | |
| 22 | { | ||
| 23 | ✗ | return kdl_str{.data = (s.data()), .len = s.size()}; | |
| 24 | } | ||
| 25 | |||
| 26 | ✗ | std::variant<integer_type, float_type, std::string> kdl_number_to_variant(kdl_number const& n) | |
| 27 | { | ||
| 28 | ✗ | switch (n.type) { | |
| 29 | ✗ | case KDL_NUMBER_TYPE_INTEGER: | |
| 30 | ✗ | return n.integer; | |
| 31 | ✗ | case KDL_NUMBER_TYPE_FLOATING_POINT: | |
| 32 | ✗ | return n.floating_point; | |
| 33 | ✗ | case KDL_NUMBER_TYPE_STRING_ENCODED: | |
| 34 | ✗ | return std::string{to_u8string_view(n.string)}; | |
| 35 | ✗ | default: | |
| 36 | ✗ | assert(false && "invalid kdl_number"); | |
| 37 | return 0; | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | ✗ | std::variant<std::monostate, bool, Number, std::string> kdl_value_to_variant(kdl_value const& val) | |
| 42 | { | ||
| 43 | ✗ | switch (val.type) { | |
| 44 | ✗ | case KDL_TYPE_NULL: | |
| 45 | ✗ | return std::monostate{}; | |
| 46 | ✗ | case KDL_TYPE_BOOLEAN: | |
| 47 | ✗ | return val.boolean; | |
| 48 | ✗ | case KDL_TYPE_NUMBER: | |
| 49 | ✗ | return Number{val.number}; | |
| 50 | ✗ | case KDL_TYPE_STRING: | |
| 51 | ✗ | return std::string{to_u8string_view(val.string)}; | |
| 52 | ✗ | default: | |
| 53 | ✗ | assert(false && "invalid kdl_value"); | |
| 54 | return std::monostate{}; | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | [[nodiscard]] | ||
| 59 | ✗ | bool emit_nodes(kdl_emitter* emitter, std::vector<Node> const& nodes) | |
| 60 | { | ||
| 61 | ✗ | for (const auto& node : nodes) | |
| 62 | { | ||
| 63 | ✗ | if (node.type_annotation.has_value()) | |
| 64 | { | ||
| 65 | ✗ | if (!kdl_emit_node_with_type( | |
| 66 | ✗ | emitter, to_kdl_str(*node.type_annotation), to_kdl_str(node.name))) | |
| 67 | { | ||
| 68 | ✗ | return false; | |
| 69 | } | ||
| 70 | } else { | ||
| 71 | ✗ | if (!kdl_emit_node(emitter, to_kdl_str(node.name))) | |
| 72 | { | ||
| 73 | ✗ | return false; | |
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | ✗ | for (const auto& arg : node.args) | |
| 78 | { | ||
| 79 | ✗ | auto v = static_cast<kdl_value>(arg); | |
| 80 | ✗ | if (!kdl_emit_arg(emitter, &v)) | |
| 81 | { | ||
| 82 | ✗ | return false; | |
| 83 | } | ||
| 84 | } | ||
| 85 | |||
| 86 | ✗ | for (const auto& [key, value] : node.properties) | |
| 87 | { | ||
| 88 | ✗ | auto v = static_cast<kdl_value>(value); | |
| 89 | ✗ | if (!kdl_emit_property(emitter, to_kdl_str(key), &v)) | |
| 90 | { | ||
| 91 | ✗ | return false; | |
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | ✗ | if (!node.children.empty()) | |
| 96 | { | ||
| 97 | ✗ | if (!kdl_start_emitting_children(emitter)) | |
| 98 | { | ||
| 99 | ✗ | return false; | |
| 100 | } | ||
| 101 | ✗ | if (emit_nodes(emitter, node.children) == false) | |
| 102 | { | ||
| 103 | ✗ | return false; | |
| 104 | } | ||
| 105 | ✗ | if (!kdl_finish_emitting_children(emitter)) | |
| 106 | { | ||
| 107 | ✗ | return false; | |
| 108 | } | ||
| 109 | } | ||
| 110 | } | ||
| 111 | |||
| 112 | ✗ | return true; | |
| 113 | } | ||
| 114 | |||
| 115 | template<typename TDefer> | ||
| 116 | struct Defer | ||
| 117 | { | ||
| 118 | TDefer t; | ||
| 119 | |||
| 120 | ✗ | explicit Defer(TDefer&& a) | |
| 121 | ✗ | : t(std::move(a)) | |
| 122 | ✗ | {} | |
| 123 | |||
| 124 | ✗ | ~Defer() | |
| 125 | { | ||
| 126 | ✗ | t(); | |
| 127 | ✗ | } | |
| 128 | |||
| 129 | Defer() = delete; | ||
| 130 | |||
| 131 | Defer(const Defer&) = delete; | ||
| 132 | Defer(Defer&&) = delete; | ||
| 133 | |||
| 134 | Defer operator=(const Defer&) = delete; | ||
| 135 | Defer operator=(Defer&&) = delete; | ||
| 136 | }; | ||
| 137 | } // namespace | ||
| 138 | |||
| 139 | |||
| 140 | |||
| 141 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 142 | // Number | ||
| 143 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 144 | |||
| 145 | |||
| 146 | ✗ | Number::Number() | |
| 147 | ✗ | : m_value{ 0ll } | |
| 148 | ✗ | {} | |
| 149 | |||
| 150 | ✗ | Number::Number(long long n) | |
| 151 | ✗ | : m_value{ n } | |
| 152 | ✗ | {} | |
| 153 | |||
| 154 | ✗ | Number::Number(long n) | |
| 155 | ✗ | : m_value{ static_cast<integer_type>(n) } | |
| 156 | ✗ | {} | |
| 157 | |||
| 158 | ✗ | Number::Number(int n) | |
| 159 | ✗ | : m_value{ static_cast<integer_type>(n) } | |
| 160 | ✗ | {} | |
| 161 | |||
| 162 | ✗ | Number::Number(short n) | |
| 163 | ✗ | : m_value{ static_cast<integer_type>(n) } | |
| 164 | ✗ | {} | |
| 165 | |||
| 166 | ✗ | Number::Number(double n) | |
| 167 | ✗ | : m_value{ n } | |
| 168 | ✗ | {} | |
| 169 | |||
| 170 | ✗ | Number::Number(float n) | |
| 171 | ✗ | : m_value{ static_cast<float_type>(n) } | |
| 172 | ✗ | {} | |
| 173 | |||
| 174 | ✗ | Number::Number(kdl_number const& n) | |
| 175 | ✗ | : m_value{ kdl_number_to_variant(n) } | |
| 176 | ✗ | {} | |
| 177 | |||
| 178 | ✗ | NumberType Number::type() const noexcept | |
| 179 | { | ||
| 180 | ✗ | return static_cast<NumberType>(m_value.index()); | |
| 181 | } | ||
| 182 | |||
| 183 | ✗ | Number::operator kdl_number() const | |
| 184 | { | ||
| 185 | kdl_number result; | ||
| 186 | ✗ | std::visit( | |
| 187 | ✗ | [&result]<typename T0>(const T0& n) { | |
| 188 | using T = std::decay_t<T0>; | ||
| 189 | if constexpr (std::is_same_v<T, integer_type>) { | ||
| 190 | ✗ | result.type = KDL_NUMBER_TYPE_INTEGER; | |
| 191 | ✗ | result.integer = n; | |
| 192 | } else if constexpr (std::is_same_v<T, float_type>) { | ||
| 193 | ✗ | result.type = KDL_NUMBER_TYPE_FLOATING_POINT; | |
| 194 | ✗ | result.floating_point = n; | |
| 195 | } else if constexpr (std::is_same_v<T, std::string>) { | ||
| 196 | ✗ | result.type = KDL_NUMBER_TYPE_STRING_ENCODED; | |
| 197 | ✗ | result.string = to_kdl_str(n); | |
| 198 | } else { | ||
| 199 | assert(false && "incomplete visit"); | ||
| 200 | result.type = KDL_NUMBER_TYPE_INTEGER; | ||
| 201 | result.integer = 0; | ||
| 202 | } | ||
| 203 | ✗ | }, | |
| 204 | ✗ | m_value); | |
| 205 | ✗ | return result; | |
| 206 | } | ||
| 207 | |||
| 208 | |||
| 209 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 210 | // HasTypeAnnotation | ||
| 211 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 212 | |||
| 213 | ✗ | HasTypeAnnotation::HasTypeAnnotation(std::string_view t) | |
| 214 | ✗ | : type_annotation{ t } | |
| 215 | ✗ | {} | |
| 216 | |||
| 217 | ✗ | void HasTypeAnnotation::remove_type_annotation() | |
| 218 | { | ||
| 219 | ✗ | type_annotation.reset(); | |
| 220 | ✗ | } | |
| 221 | |||
| 222 | |||
| 223 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 224 | // Value | ||
| 225 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 226 | |||
| 227 | |||
| 228 | ✗ | Value::Value(bool b) | |
| 229 | ✗ | : m_value{ b } | |
| 230 | ✗ | {} | |
| 231 | |||
| 232 | ✗ | Value::Value(std::string_view s) | |
| 233 | ✗ | : m_value{ std::string{s} } | |
| 234 | ✗ | {} | |
| 235 | |||
| 236 | ✗ | Value::Value(std::string s) | |
| 237 | ✗ | : m_value{ std::move(s) } | |
| 238 | ✗ | {} | |
| 239 | |||
| 240 | ✗ | Value::Value(char const* s) | |
| 241 | ✗ | : m_value{ std::string{s} } | |
| 242 | ✗ | {} | |
| 243 | |||
| 244 | ✗ | Value::Value(Number n) | |
| 245 | ✗ | : m_value{ std::move(n) } | |
| 246 | ✗ | {} | |
| 247 | |||
| 248 | ✗ | Value::Value(std::string_view ta, bool b) | |
| 249 | : HasTypeAnnotation{ ta } | ||
| 250 | ✗ | , m_value{ b } | |
| 251 | ✗ | {} | |
| 252 | |||
| 253 | ✗ | Value::Value(std::string_view ta, std::string_view s) | |
| 254 | : HasTypeAnnotation{ ta } | ||
| 255 | ✗ | , m_value{ std::string{s} } | |
| 256 | ✗ | {} | |
| 257 | |||
| 258 | ✗ | Value::Value(std::string_view ta, std::string s) | |
| 259 | : HasTypeAnnotation{ ta }, | ||
| 260 | ✗ | m_value{ std::move(s) } | |
| 261 | ✗ | {} | |
| 262 | |||
| 263 | ✗ | Value::Value(std::string_view ta, Number n) | |
| 264 | : HasTypeAnnotation{ ta }, | ||
| 265 | ✗ | m_value{ std::move(n) } | |
| 266 | ✗ | {} | |
| 267 | |||
| 268 | ✗ | Value::Value(kdl_value const& val) | |
| 269 | ✗ | : m_value(kdl_value_to_variant(val)) | |
| 270 | { | ||
| 271 | ✗ | if (val.type_annotation.data != nullptr) { | |
| 272 | ✗ | type_annotation = to_u8string_view(val.type_annotation); | |
| 273 | } | ||
| 274 | ✗ | } | |
| 275 | |||
| 276 | ✗ | Value& Value::operator=(bool b) | |
| 277 | { | ||
| 278 | ✗ | m_value = b; | |
| 279 | ✗ | return *this; | |
| 280 | } | ||
| 281 | |||
| 282 | ✗ | Value& Value::operator=(std::string_view s) | |
| 283 | { | ||
| 284 | ✗ | m_value = std::string{ s }; | |
| 285 | ✗ | return *this; | |
| 286 | } | ||
| 287 | |||
| 288 | ✗ | Value& Value::operator=(std::string s) | |
| 289 | { | ||
| 290 | ✗ | m_value = std::move(s); | |
| 291 | ✗ | return *this; | |
| 292 | } | ||
| 293 | |||
| 294 | ✗ | Value& Value::operator=(Number const& n) | |
| 295 | { | ||
| 296 | ✗ | m_value = n; | |
| 297 | ✗ | return *this; | |
| 298 | } | ||
| 299 | |||
| 300 | ✗ | Value& Value::operator=(Number&& n) | |
| 301 | { | ||
| 302 | ✗ | m_value = std::move(n); | |
| 303 | ✗ | return *this; | |
| 304 | } | ||
| 305 | |||
| 306 | ✗ | void Value::set_to_null() | |
| 307 | { | ||
| 308 | ✗ | m_value = std::monostate{}; | |
| 309 | ✗ | } | |
| 310 | |||
| 311 | ✗ | Type Value::type() const noexcept | |
| 312 | { | ||
| 313 | ✗ | return static_cast<Type>(m_value.index()); | |
| 314 | } | ||
| 315 | |||
| 316 | ✗ | const Number& Value::as_number() const | |
| 317 | { | ||
| 318 | ✗ | if (std::holds_alternative<Number>(m_value)) { | |
| 319 | ✗ | return std::get<Number>(m_value); | |
| 320 | } | ||
| 321 | else { | ||
| 322 | ✗ | static const Number missing_number = 0; | |
| 323 | ✗ | return missing_number; | |
| 324 | } | ||
| 325 | } | ||
| 326 | |||
| 327 | ✗ | const std::string& Value::as_string() const | |
| 328 | { | ||
| 329 | ✗ | if (std::holds_alternative<std::string>(m_value)) { | |
| 330 | ✗ | return std::get<std::string>(m_value); | |
| 331 | } | ||
| 332 | else { | ||
| 333 | ✗ | static const std::string missing_string = ""; | |
| 334 | ✗ | return missing_string; | |
| 335 | } | ||
| 336 | } | ||
| 337 | |||
| 338 | ✗ | bool Value::as_bool() const | |
| 339 | { | ||
| 340 | ✗ | if (std::holds_alternative<bool>(m_value)) { | |
| 341 | ✗ | return std::get<bool>(m_value); | |
| 342 | } | ||
| 343 | else { | ||
| 344 | ✗ | return false; | |
| 345 | } | ||
| 346 | } | ||
| 347 | |||
| 348 | ✗ | bool Value::is_null() const | |
| 349 | { | ||
| 350 | ✗ | return std::holds_alternative<std::monostate>(m_value); | |
| 351 | } | ||
| 352 | |||
| 353 | ✗ | Value::operator kdl_value() const | |
| 354 | { | ||
| 355 | kdl_value result; | ||
| 356 | |||
| 357 | ✗ | std::visit([&result](const auto& v) | |
| 358 | { | ||
| 359 | using T = std::decay_t<decltype(v)>; | ||
| 360 | if constexpr (std::is_same_v<T, bool>) | ||
| 361 | { | ||
| 362 | ✗ | result.type = KDL_TYPE_BOOLEAN; | |
| 363 | ✗ | result.boolean = v; | |
| 364 | } else if constexpr (std::is_same_v<T, Number>) | ||
| 365 | { | ||
| 366 | ✗ | result.type = KDL_TYPE_NUMBER; | |
| 367 | ✗ | result.number = static_cast<kdl_number>(v); | |
| 368 | } else if constexpr (std::is_same_v<T, std::string>) | ||
| 369 | { | ||
| 370 | ✗ | result.type = KDL_TYPE_STRING; | |
| 371 | ✗ | result.string = to_kdl_str(v); | |
| 372 | } else { | ||
| 373 | ✗ | result.type = KDL_TYPE_NULL; | |
| 374 | } | ||
| 375 | ✗ | }, | |
| 376 | ✗ | m_value); | |
| 377 | |||
| 378 | ✗ | if (type_annotation.has_value()) | |
| 379 | { | ||
| 380 | ✗ | result.type_annotation = to_kdl_str(*type_annotation); | |
| 381 | } | ||
| 382 | else | ||
| 383 | { | ||
| 384 | ✗ | result.type_annotation = {.data = nullptr, .len = 0}; | |
| 385 | } | ||
| 386 | |||
| 387 | ✗ | return result; | |
| 388 | } | ||
| 389 | |||
| 390 | |||
| 391 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 392 | // Node | ||
| 393 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 394 | |||
| 395 | |||
| 396 | ✗ | Node::Node(std::string_view name) | |
| 397 | ✗ | : name{ name } | |
| 398 | ✗ | {} | |
| 399 | |||
| 400 | ✗ | Node::Node(std::string_view ta, std::string_view name) | |
| 401 | : HasTypeAnnotation{ ta } | ||
| 402 | ✗ | , name{ name } | |
| 403 | ✗ | {} | |
| 404 | |||
| 405 | ✗ | Node::Node(std::string_view name, std::vector<Value> args, std::map<std::string, Value, std::less<>> properties, std::vector<Node> children) | |
| 406 | ✗ | : name{ name } | |
| 407 | ✗ | , args{ std::move(args) } | |
| 408 | ✗ | , properties{ std::move(properties) } | |
| 409 | ✗ | , children{ std::move(children) } | |
| 410 | ✗ | {} | |
| 411 | |||
| 412 | ✗ | Node::Node(std::string_view ta, std::string_view name, std::vector<Value> args, std::map<std::string, Value, std::less<>> properties, std::vector<Node> children) | |
| 413 | : HasTypeAnnotation{ ta } | ||
| 414 | ✗ | , name{ name } | |
| 415 | ✗ | , args{ std::move(args) } | |
| 416 | ✗ | , properties{ std::move(properties) } | |
| 417 | ✗ | , children{ std::move(children) } | |
| 418 | ✗ | {} | |
| 419 | |||
| 420 | |||
| 421 | |||
| 422 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 423 | // Document | ||
| 424 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 425 | |||
| 426 | ✗ | Document::Document(std::vector<Node> nodes) | |
| 427 | ✗ | : nodes{ std::move(nodes) } | |
| 428 | ✗ | {} | |
| 429 | |||
| 430 | ✗ | Document::Document(std::initializer_list<Node> nodes) | |
| 431 | ✗ | : nodes{ nodes } | |
| 432 | ✗ | {} | |
| 433 | |||
| 434 | ✗ | std::optional<std::string> Document::to_string() const | |
| 435 | { | ||
| 436 | ✗ | return to_string(Version::kdl_1); | |
| 437 | } | ||
| 438 | |||
| 439 | ✗ | std::optional<std::string> Document::to_string(Version version) const | |
| 440 | { | ||
| 441 | ✗ | kdl_emitter_options opts = KDL_DEFAULT_EMITTER_OPTIONS; | |
| 442 | |||
| 443 | ✗ | if (version == Version::kdl_1) opts.version = KDL_VERSION_1; | |
| 444 | ✗ | if (version == Version::kdl_2) opts.version = KDL_VERSION_2; | |
| 445 | |||
| 446 | ✗ | kdl_emitter* emitter = kdl_create_buffering_emitter(&opts); | |
| 447 | ✗ | if (emitter == nullptr) | |
| 448 | { | ||
| 449 | ✗ | assert(false && "Error initializing the KDL emitter"); | |
| 450 | return std::nullopt; | ||
| 451 | } | ||
| 452 | ✗ | auto defer_emitter = Defer{[&]{ kdl_destroy_emitter(emitter); }}; | |
| 453 | |||
| 454 | ✗ | if (false == emit_nodes(emitter, nodes)) | |
| 455 | { | ||
| 456 | ✗ | return std::nullopt; | |
| 457 | } | ||
| 458 | |||
| 459 | ✗ | auto result = std::string{to_u8string_view(kdl_get_emitter_buffer(emitter))}; | |
| 460 | ✗ | return result; | |
| 461 | ✗ | } | |
| 462 | |||
| 463 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 464 | // DocumentResult | ||
| 465 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 466 | |||
| 467 | |||
| 468 | ✗ | DocumentResult::DocumentResult(Document doc) | |
| 469 | ✗ | : document{ std::move(doc) } | |
| 470 | ✗ | {} | |
| 471 | |||
| 472 | ✗ | DocumentResult::DocumentResult(std::string err) | |
| 473 | ✗ | : error{ std::move(err) } | |
| 474 | ✗ | {} | |
| 475 | |||
| 476 | |||
| 477 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 478 | // Parsing | ||
| 479 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||
| 480 | |||
| 481 | namespace | ||
| 482 | { | ||
| 483 | |||
| 484 | ✗ | DocumentResult Document_read_from(kdl_parser* parser) | |
| 485 | { | ||
| 486 | ✗ | Document doc; | |
| 487 | ✗ | auto* node_list = &doc.nodes; | |
| 488 | ✗ | Node* current_node = nullptr; | |
| 489 | ✗ | std::vector<Node*> stack; | |
| 490 | |||
| 491 | while (true) | ||
| 492 | { | ||
| 493 | ✗ | auto* ev = kdl_parser_next_event(parser); | |
| 494 | |||
| 495 | ✗ | switch (ev->event) | |
| 496 | { | ||
| 497 | ✗ | case KDL_EVENT_EOF: | |
| 498 | ✗ | return DocumentResult{ doc }; | |
| 499 | ✗ | case KDL_EVENT_PARSE_ERROR: | |
| 500 | ✗ | return DocumentResult{ static_cast<std::string>(to_u8string_view(ev->value.string)) }; | |
| 501 | ✗ | case KDL_EVENT_START_NODE: | |
| 502 | { | ||
| 503 | ✗ | auto name = to_u8string_view(ev->name); | |
| 504 | ✗ | if (ev->value.type_annotation.data != nullptr) | |
| 505 | { | ||
| 506 | ✗ | auto ta = to_u8string_view(ev->value.type_annotation); | |
| 507 | ✗ | current_node = &node_list->emplace_back(ta, name); | |
| 508 | } | ||
| 509 | else | ||
| 510 | { | ||
| 511 | ✗ | current_node = &node_list->emplace_back(name); | |
| 512 | } | ||
| 513 | ✗ | node_list = ¤t_node->children; | |
| 514 | ✗ | stack.push_back(current_node); | |
| 515 | ✗ | break; | |
| 516 | } | ||
| 517 | ✗ | case KDL_EVENT_END_NODE: | |
| 518 | ✗ | stack.pop_back(); | |
| 519 | ✗ | if (stack.empty()) | |
| 520 | { | ||
| 521 | ✗ | current_node = nullptr; | |
| 522 | ✗ | node_list = &doc.nodes; | |
| 523 | } | ||
| 524 | else | ||
| 525 | { | ||
| 526 | ✗ | current_node = stack.back(); | |
| 527 | ✗ | node_list = ¤t_node->children; | |
| 528 | } | ||
| 529 | ✗ | break; | |
| 530 | ✗ | case KDL_EVENT_ARGUMENT: | |
| 531 | ✗ | current_node->args.emplace_back(ev->value); | |
| 532 | ✗ | break; | |
| 533 | ✗ | case KDL_EVENT_PROPERTY: | |
| 534 | ✗ | current_node->properties[std::string{ to_u8string_view(ev->name) }] = Value{ ev->value }; | |
| 535 | ✗ | break; | |
| 536 | ✗ | case KDL_EVENT_COMMENT: | |
| 537 | // ignore comments | ||
| 538 | ✗ | break; | |
| 539 | ✗ | default: | |
| 540 | ✗ | assert(false && "Invalid event from kdl_parser"); | |
| 541 | break; | ||
| 542 | } | ||
| 543 | ✗ | } | |
| 544 | ✗ | } | |
| 545 | } | ||
| 546 | |||
| 547 | |||
| 548 | ✗ | DocumentResult parse(std::string_view kdl_text) | |
| 549 | { | ||
| 550 | ✗ | return parse(kdl_text, Version::any); | |
| 551 | } | ||
| 552 | |||
| 553 | ✗ | DocumentResult parse(std::string_view kdl_text, Version version) | |
| 554 | { | ||
| 555 | ✗ | kdl_parse_option opts = KDL_DEFAULTS; | |
| 556 | |||
| 557 | ✗ | switch (version) | |
| 558 | { | ||
| 559 | ✗ | case Version::kdl_1: | |
| 560 | ✗ | opts = KDL_READ_VERSION_1; | |
| 561 | ✗ | break; | |
| 562 | ✗ | case Version::kdl_2: | |
| 563 | ✗ | opts = KDL_READ_VERSION_2; | |
| 564 | ✗ | break; | |
| 565 | ✗ | case Version::any: | |
| 566 | { | ||
| 567 | ✗ | auto ret = parse(kdl_text, Version::kdl_2); | |
| 568 | ✗ | if (ret.document.has_value()) | |
| 569 | { | ||
| 570 | ✗ | return ret; | |
| 571 | } | ||
| 572 | else | ||
| 573 | { | ||
| 574 | ✗ | return parse(kdl_text, Version::kdl_1); | |
| 575 | } | ||
| 576 | ✗ | } | |
| 577 | |||
| 578 | ✗ | default: | |
| 579 | ✗ | assert(false && "unhandled case"); | |
| 580 | break; | ||
| 581 | } | ||
| 582 | |||
| 583 | ✗ | const kdl_str text = {.data = (kdl_text.data()), .len = kdl_text.size()}; | |
| 584 | ✗ | kdl_parser* parser = kdl_create_string_parser(text, opts); | |
| 585 | ✗ | if (parser == nullptr) | |
| 586 | { | ||
| 587 | ✗ | assert(false && "Error initializing the KDL parser"); | |
| 588 | return DocumentResult("internal error"); | ||
| 589 | } | ||
| 590 | ✗ | auto defer_parser = Defer{[&]{ kdl_destroy_parser(parser); }}; | |
| 591 | |||
| 592 | ✗ | auto doc = Document_read_from(parser); | |
| 593 | ✗ | return doc; | |
| 594 | ✗ | } | |
| 595 | |||
| 596 | } | ||
| 597 |