| 425 | } |
| 426 | |
| 427 | Rv<Expr> |
| 428 | Config::parse_expr(YAML::Node expr_node) |
| 429 | { |
| 430 | std::string_view expr_tag(expr_node.Tag()); |
| 431 | |
| 432 | // This is the base entry method, so it needs to handle all cases, although most of them |
| 433 | // will be delegated. Handle the direct / simple special cases here. |
| 434 | |
| 435 | if (expr_node.IsNull()) { // explicit NULL |
| 436 | return Expr{NIL_FEATURE}; |
| 437 | } |
| 438 | |
| 439 | // If explicitly marked a literal, then no further processing should be done. |
| 440 | if (0 == strcasecmp(expr_tag, LITERAL_TAG)) { |
| 441 | if (!expr_node.IsScalar()) { |
| 442 | return Errata(S_ERROR, R"("!{}" tag used on value at {} which is not a string as required for a literal.)", LITERAL_TAG, |
| 443 | expr_node.Mark()); |
| 444 | } |
| 445 | return Expr{FeatureView::Literal(this->localize(expr_node.Scalar()))}; |
| 446 | } else if (0 == strcasecmp(expr_tag, DURATION_TAG)) { |
| 447 | if (!expr_node.IsScalar()) { |
| 448 | return Errata(S_ERROR, R"("!{}" tag used on value at {} which is not a string as required for a literal.)", LITERAL_TAG, |
| 449 | expr_node.Mark()); |
| 450 | } |
| 451 | auto &&[dt, dt_errata]{Feature{expr_node.Scalar()}.as_duration()}; |
| 452 | return {Expr(dt), std::move(dt_errata)}; |
| 453 | } else if (0 != strcasecmp(expr_tag, "?"_sv) && 0 != strcasecmp(expr_tag, "!"_sv)) { |
| 454 | return Errata(S_ERROR, R"("{}" tag for extractor expression is not supported.)", expr_tag); |
| 455 | } |
| 456 | |
| 457 | if (expr_node.IsScalar()) { |
| 458 | return this->parse_scalar_expr(expr_node); |
| 459 | } |
| 460 | if (!expr_node.IsSequence()) { |
| 461 | return Errata(S_ERROR, "Feature expression is not properly structured."); |
| 462 | } |
| 463 | |
| 464 | // It's a sequence, handle the various cases. |
| 465 | if (expr_node.size() == 0) { |
| 466 | return Expr{NIL_FEATURE}; |
| 467 | } |
| 468 | if (expr_node.size() == 1) { |
| 469 | return this->parse_scalar_expr(expr_node[0]); |
| 470 | } |
| 471 | |
| 472 | if (expr_node[1].IsMap()) { // base expression with modifiers. |
| 473 | return this->parse_expr_with_mods(expr_node); |
| 474 | } |
| 475 | |
| 476 | // Else, after all this, it's a tuple, treat each element as an expression. |
| 477 | ActiveType l_types; |
| 478 | bool literal_p = true; // Is the entire sequence literal? |
| 479 | std::vector<Expr> xa; |
| 480 | xa.reserve(expr_node.size()); |
| 481 | for (auto const &child : expr_node) { |
| 482 | auto &&[expr, errata]{this->parse_expr(child)}; |
| 483 | if (!errata.is_ok()) { |
| 484 | errata.note("While parsing feature expression list at {}.", expr_node.Mark()); |
no test coverage detected