10import reflect.serialize;
11export import fabric.grammar;
12import fabric.grammar.operators;
19#define TERMINAL(C) using C##_t = fabric::terminal<#C[0]>; static C##_t C
20#define TERMINAL_DIGIT(C) using d##C##_t = fabric::terminal<#C[0]>; static d##C##_t d##C
21#define TERMINAL_W_NAME(C, NAME) using NAME##_t = fabric::terminal<C>; static NAME##_t NAME
23#define RULE_EXPR__(...) using rule = decltype(__VA_ARGS__);}
24#define RULE(NAME) struct NAME: public fabric::node_t { \
25 static constexpr const char* name = #NAME; \
26 static constexpr bool transient = false; \
27 using sptr = std::shared_ptr<NAME>; \
28 NAME(): fabric::node_t(refl::type_id<NAME>) {} \
31#define TRULE(NAME) struct NAME: public fabric::node_t { \
32 static constexpr const char* name = #NAME; \
33 static constexpr bool transient = true; \
34 using sptr = std::shared_ptr<NAME>; \
35 NAME(): fabric::node_t(refl::type_id<NAME>) {} \
38#define RULE_ACTION__(...) static void action(const sptr& $node) __VA_ARGS__ }
39#define ARULE_DATA_TYPE__(...) __VA_ARGS__ data{}; RULE_ACTION__
40#define RULE_EXPR_W_ACTION__(...) using rule = decltype(__VA_ARGS__); ARULE_DATA_TYPE__
41#define ARULE(NAME) struct NAME: public fabric::node_t { \
42 static constexpr const char* name = #NAME; \
43 static constexpr bool transient = false; \
44 using sptr = std::shared_ptr<NAME>; \
45 NAME(): fabric::node_t(refl::type_id<NAME>) {} \
48#define GRAMMAR(NAME) \
50namespace grammar_metadata { \
52 static constexpr const char* name = #NAME; \
55struct NAME: grammar_metadata::NAME
57#define START(RULE) using start = RULE
152 RULE(skip_wn)(*(whitespace | newline | return_));
154 RULE(comma_separator)(*(whitespace | newline | return_), comma, *(whitespace | newline | return_));
155 RULE(colon_asigner)(*(whitespace | newline | return_), colon, *(whitespace | newline | return_));
156 RULE(braces_begin)(*(whitespace | newline | return_), left_braces, *(whitespace | newline | return_));
157 RULE(braces_end)(*(whitespace | newline | return_), right_braces, *(whitespace | newline | return_));
159 RULE(end_of_declaration)(*(whitespace | newline | return_), semicolon, *(whitespace | newline | return_));
161 TRULE(digit_excluding_zero) (d1 | d2 | d3 | d4 | d5 | d6 | d7 | d8 | d9);
163 TRULE(digit) (d0 | digit_excluding_zero{});
165 TRULE(hex_digit_chars)(
166 a | b | c | d | e | f |
167 A | B | C | D | E | F);
168 TRULE(hex_digit)(hex_digit_chars{} | digit{});
170 RULE(number) (~(plus | minus), ((*digit{}, dot, +digit{}) | +digit{}));
172 TRULE(alpha) (a | b | c | d | e | f | g | h | i | j | k | l | m | n | o | p | q | r | s | t | u | v | w | x | y | z );
173 TRULE(ALPHA) (A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z );
175 TRULE(alphanum) (alpha{} | ALPHA{} | digit{});
177 TRULE(tss_identifier) ((alpha{} | ALPHA{} | minus | underscore), *(alphanum{} | minus | underscore));
179 TRULE(tss_single_quoted_str_char)(
180 alphanum{} | colon | semicolon | plus | minus | underscore | shebang | dot | comma | asterisc | whitespace
181 | newline | return_ | double_quote | left_brackets | right_brackets | left_braces
182 | right_braces | left_parens | right_parens | left_angle_brackets | right_angle_brackets
185 TRULE(tss_single_quoted_str) (!quote, *tss_single_quoted_str_char{}, !quote);
187 TRULE(tss_double_quoted_str_char)(
188 alphanum{} | colon | semicolon | plus | minus | underscore | shebang | dot | comma | asterisc | whitespace
189 | newline | return_ | quote | left_brackets | right_brackets | left_braces
190 | right_braces | left_parens | right_parens | left_angle_brackets | right_angle_brackets
193 TRULE(tss_double_quoted_str) (!double_quote, *tss_double_quoted_str_char{}, !double_quote);
196 RULE(tss_class_selector) (dot, tss_identifier{});
198 RULE(tss_id_selector) (shebang, tss_identifier{});
200 RULE(tss_pseudo_state_selector) (colon, tss_identifier{});
202 RULE(tss_element_selector) (tss_identifier{}, *(forward_slash, tss_identifier{}));
204 struct selector_data {
207 ARULE(tss_descendent_selector_item) (tss_element_selector{}, *(tss_class_selector{} | tss_id_selector{} | tss_pseudo_state_selector{}))
209 auto& selector = $node->data.selector;
211 if (not $node->children.empty()) {
212 if ($node->children[0]->is_type<tss_element_selector>()) {
213 const auto *es = $node->children[0]->as<tss_element_selector>();
214 selector.component = es->children[0]->text;
216 std::size_t pos = selector.component.find(
"/");
217 while (pos != std::string::npos) {
218 selector.component.replace(pos, 1,
"::");
219 pos = selector.component.find(
"/", pos + 2);
223 for (std::size_t i = 1; i < $node->children.size(); ++i) {
224 auto& child = $node->children[i];
225 if (child->is_type<tss_id_selector>()) {
226 const auto *is = child->as<tss_id_selector>();
227 selector.tags.insert(is->children[0]->text.substr(1));
228 }
else if (child->is_type<tss_pseudo_state_selector>()) {
229 const auto *ps = child->as<tss_pseudo_state_selector>();
230 selector.pseudo_states.insert(ps->children[0]->text.substr(1));
239 RULE(tss_children_selector_item) (!right_angle_brackets, !skip_wn{}, tss_descendent_selector_item{});
241 struct combined_selector_data {
243 std::string key_element{};
245 ARULE(tss_combined_selector) (tss_descendent_selector_item{}, !skip_wn{}, *((tss_children_selector_item{} | tss_descendent_selector_item{}), !skip_wn{}))
246 (combined_selector_data)({
247 auto& selector = $node->data.selector;
248 auto& key = $node->data.key_element;
250 selector.selectors.emplace_back(
252 $node->children[0]->as<tss_descendent_selector_item>()->data.selector
255 if ($node->children.size() > 1) {
256 for (std::size_t i = 1; i < $node->children.size(); ++i) {
257 const auto& child = $node->children[i];
258 if (child->is_type<tss_children_selector_item>()) {
259 const auto *cs = child->as<tss_children_selector_item>()
260 ->children[0]->as<tss_descendent_selector_item>();
261 selector.selectors.emplace_back(
265 }
else if (child->is_type<tss_descendent_selector_item>()) {
266 const auto *ss = child->as<tss_descendent_selector_item>();
267 selector.selectors.emplace_back(
275 key = selector.selectors.back().second.component;
278 TRULE(tss_grouping_selector) (*(tss_combined_selector{}, !comma_separator{}), tss_combined_selector{}, !skip_wn{});
280 struct selector_list_data {
281 std::vector<cydui::StyleRuleCombinedSelector> selectors{};
282 std::vector<std::string> selector_keys{};
284 ARULE(tss_selector) (asterisc | tss_grouping_selector{})
285 (selector_list_data)({
286 for (
const auto& child: $node->children) {
287 if (child->is_type<tss_combined_selector>()) {
288 const auto* cs = child->as<tss_combined_selector>();
289 $node->data.selectors.emplace_back(cs->data.selector);
290 $node->data.selector_keys.emplace_back(cs->data.key_element);
296 struct tss_decl_expression_list;
298 RULE(tss_decl_function_call) (tss_identifier{}, left_parens, *(fabric::recurse<tss_decl_expression_list>{}, !comma_separator{}), ~fabric::recurse<tss_decl_expression_list>{}, right_parens);
300 ARULE(tss_decl_color_literal)
301 (shebang, hex_digit{}, hex_digit{}, hex_digit{}, hex_digit{}, hex_digit{}, hex_digit{},
302 ~(hex_digit{}, hex_digit{}))
307 struct number_literal_data {
311 ARULE(tss_decl_number_literal) (number{} , ~tss_identifier{})
312 (number_literal_data)({
313 const std::string& num = $node->children[0]->children[0]->text;
315 $node->data.value = std::strtod(num.c_str(), &end);
317 if ($node->children.size() > 1) {
318 $node->data.unit = $node->children[1]->text;
322 ARULE(tss_decl_string_literal) (tss_single_quoted_str{} | tss_double_quoted_str{})
324 $node->data = $node->children[0]->text;
327 ARULE(tss_decl_expression)(tss_decl_color_literal{} | tss_decl_function_call{} | tss_identifier{} | tss_decl_number_literal{} | tss_decl_string_literal{})
329 const auto& child = $node->children[0];
330 refl::any& value = $node->data;
332 if (child->is_type<tss_decl_color_literal>()) {
333 value = refl::any::make<color::Color>(child->as<tss_decl_color_literal>()->data);
334 }
else if (child->is_type<tss_decl_function_call>()) {
335 }
else if (child->is_type<tss_decl_string_literal>()) {
336 value = refl::any::make<std::string>(child->as<tss_decl_string_literal>()->data);
337 }
else if (child->is_type<tss_decl_number_literal>()) {
338 auto d = child->as<tss_decl_number_literal>()->data;
339 if (d.unit.empty()) {
340 value = refl::any::make<double>(d.value);
341 }
else if (d.unit ==
"px") {
342 value = refl::any::make<cydui::dimensions::screen_measure>(d.value);
347 ARULE(tss_decl_expression_list)(*(tss_decl_expression{}, !whitespace, !skip_wn{}), tss_decl_expression{}, !skip_wn{})
349 refl::any& value = $node->data;
351 if ($node->children.size() == 1) {
352 value = $node->children[0]->as<tss_decl_expression>()->data;
354 std::vector<refl::any> values{};
355 for (
const auto& child: $node->children) {
356 values.push_back(child->as<tss_decl_expression>()->data);
358 const auto& vs = values;
359 value = refl::any::make<std::vector<refl::any>>(values);
363 RULE(tss_declaration_name) (tss_identifier{});
365 struct declaration_data {
369 ARULE(tss_declaration)(tss_declaration_name{}, !colon_asigner{}, tss_decl_expression_list{}, !end_of_declaration{})
371 auto& [name, value] = $node->data;
372 name = $node->children[0]->children[0]->text;
373 value = $node->children[1]->as<tss_decl_expression_list>()->data;
376 struct declaration_list_data {
377 refl::archive archive{};
379 ARULE(tss_declaration_list)(*(tss_declaration{}))
380 (declaration_list_data)({
381 refl::archive& archive = $node->data.archive;
382 for (
const auto& decl: $node->children) {
383 const auto&[name, value] = decl->as<tss_declaration>()->data;
384 archive[name] = value;
389 ARULE(tss_rule)(!skip_wn{}, tss_selector{}, !braces_begin{}, tss_declaration_list{}, !braces_end{})
391 $node->data = std::make_shared<cydui::StyleRule>();
393 if ($node->children[0]->is_type<tss_selector>()) {
394 const auto* sel = $node->children[0]->as<tss_selector>();
395 $node->data->selectors_ = sel->data.selectors;
396 $node->data->relevant_components_ = sel->data.selector_keys;
398 if ($node->children[1]->is_type<tss_declaration_list>()) {
399 const auto* sel = $node->children[1]->as<tss_declaration_list>();
400 $node->data->properties_ = sel->data.archive;
404 struct stylesheet_data {
405 std::vector<cydui::StyleRule::sptr> rules{};
407 ARULE(tss_stylesheet)(*tss_rule())
409 for (
const auto& child: $node->children) {
410 $node->data.rules.push_back(child->as<tss_rule>()->data);
414 START(tss_stylesheet);
418export namespace lang::tss {
419 using parse_result = fabric::parse_result<syntax::tss>;
421 template <
typename Input>
422 parse_result parse(
const Input& input_) {
423 auto [ok, ast, log] = fabric::parse<syntax::tss>(input_);
425 return {ok, ast, log};
#define TERMINAL_W_NAME(C, NAME)
#define TERMINAL_DIGIT(C)
static Color from_str(const std::string &data)
std::shared_ptr< StyleRule > sptr