HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
selector_parser.hpp
1
2
3#pragma once
4
5#include "../parser/parser.hpp"
6#include "../macros.hpp"
7#include <iterator>
8
9namespace hi { inline namespace v1 {
10
11[[nodiscard]] constexpr static lexer_config theme_selector_lexer_config() noexcept
12{
13 auto r = lexer_config{};
14 r.has_double_quote_string_literal = 1;
15 r.has_color_literal = 1;
16 r.filter_white_space = 1;
17 r.minus_in_identifier = 1;
18 return r;
19}
20
21template<std::forward_iterator It, std::sentinel_for<It> ItEnd>
22[[nodiscard]] constexpr std::parse_expected<theme_selector_segment, std::string> parse_selector_segment(It &it, ItEnd last)
23{
24 hi_assert(it != last);
25
26 if (it[0] != '/') {
27 return std::nullopt;
28 }
29
30 if (it == last or it[1] != token::id) {
31 return std::unexpected{std::format("{}: Expected a widg
32 et name after '/', got '{}'.", token_location(it + 1, last), it[1])};
33 }
34
35 auto r = theme_selector_segment{static_cast<std::string>(it[1])};
36
37 it += 2;
38 while (it != last and *it != '/') {
39 if (auto id = parse_selector_id(it, last)) {
40 r.id = *id;
41 continue;
42 } else if (id.has_error()) {
43 return std::unexpected{id.error()};
44 }
45
46 if (auto class_name = parse_selector_class(it, last)) {
47 r.classes.push_back(*class_name);
48 continue;
49 } else if (class_name.has_error()) {
50 return std::unexpected{class_name.error()};
51 }
52
53 if (auto attribute = parse_selector_attribute(it, last)) {
54 r.attributes.push_back(*attribute);
55 continue;
56 } else if (attribute.has_error()) {
57 return std::unexpected{attribute.error()};
58 }
59 }
60
61 return r;
62}
63
64template<std::forward_iterator It, std::sentinel_for<It> ItEnd>
65[[nodiscard]] constexpr std::expected<theme_selector, std::string> parse_selector(It first, ItEnd last)
66{
67 constexpr auto config = [] {
68 auto r = lexer_config{};
69 r.has_double_quote_string_literal = 1;
70 r.has_color_literal = 1;
71 r.filter_white_space = 1;
72 r.minus_in_identifier = 1;
73 return r;
74 }();
75
76 auto lexer_it = lexer<config>.parse(first, last);
77 auto token_it = make_lookahead_iterator<4>(lexer_it);
78
80 while (token_it != std::sentinel) {
81 if (auto segment = parse_selector_segment(token_it, std::sentinel)) {
82 if (not r.empty()) {
83 // Only the attributes for the leaf segment are interesting.
84 r.back().attributes.clear();
85 }
86 r.push_back(std::move(*segment));
87
88 } else if (segment.has_error()) {
89 return std::unexpected{segment.error()};
90
91 } else {
92 return std::unexpected{std::format("{}: Unexpected token '{}'.", token_location(token_it, std::sentinel), *token_it)};
93 }
94 }
95
96 return theme_selector{std::move(r)};
97}
98
99}} // namespace hi::v1
The HikoGUI namespace.
Definition array_generic.hpp:20
hi_export constexpr std::string token_location(It &it, ItEnd last, std::string_view path) noexcept
Create a location string for error messages.
Definition token.hpp:163
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
T back(T... args)
T move(T... args)
T push_back(T... args)
T unexpected(T... args)