i_slint_compiler/parser/
element.rs1use super::document::parse_qualified_name;
7use super::expressions::parse_expression;
8use super::prelude::*;
9use super::r#type::parse_type;
10use super::statements::parse_statement;
11
12#[cfg_attr(test, parser_test)]
13pub fn parse_element(p: &mut impl Parser) -> bool {
19 let mut p = p.start_node(SyntaxKind::Element);
20 if !parse_qualified_name(&mut *p) {
21 return if p.test(SyntaxKind::LBrace) {
22 parse_element_content(&mut *p);
24 p.expect(SyntaxKind::RBrace)
25 } else {
26 false
27 };
28 }
29
30 if !p.expect(SyntaxKind::LBrace) {
31 return false;
32 }
33
34 parse_element_content(&mut *p);
35
36 p.expect(SyntaxKind::RBrace)
37}
38
39#[cfg_attr(test, parser_test)]
40pub fn parse_element_content(p: &mut impl Parser) {
56 let mut had_parse_error = false;
57 loop {
58 match p.nth(0).kind() {
59 SyntaxKind::RBrace => return,
60 SyntaxKind::Eof => return,
61 SyntaxKind::Identifier => match p.nth(1).kind() {
62 SyntaxKind::Colon => parse_property_binding(&mut *p),
63 SyntaxKind::ColonEqual | SyntaxKind::LBrace => {
64 had_parse_error |= !parse_sub_element(&mut *p)
65 }
66 SyntaxKind::FatArrow | SyntaxKind::LParent if p.peek().as_str() != "if" => {
67 parse_callback_connection(&mut *p)
68 }
69 SyntaxKind::DoubleArrow => parse_two_way_binding(&mut *p),
70 SyntaxKind::Identifier if p.peek().as_str() == "for" => {
71 parse_repeated_element(&mut *p);
72 }
73 SyntaxKind::Identifier
74 if p.peek().as_str() == "callback"
75 || (p.peek().as_str() == "pure" && p.nth(1).as_str() == "callback") =>
76 {
77 parse_callback_declaration(&mut *p);
78 }
79 SyntaxKind::Identifier
80 if p.peek().as_str() == "function"
81 || (matches!(p.peek().as_str(), "public" | "pure" | "protected")
82 && p.nth(1).as_str() == "function")
83 || (matches!(p.nth(1).as_str(), "public" | "pure" | "protected")
84 && p.nth(2).as_str() == "function") =>
85 {
86 parse_function(&mut *p);
87 }
88 SyntaxKind::Identifier | SyntaxKind::Star if p.peek().as_str() == "animate" => {
89 parse_property_animation(&mut *p);
90 }
91 SyntaxKind::Identifier if p.peek().as_str() == "changed" => {
92 parse_changed_callback(&mut *p);
93 }
94 SyntaxKind::LAngle | SyntaxKind::Identifier if p.peek().as_str() == "property" => {
95 parse_property_declaration(&mut *p);
96 }
97 SyntaxKind::Identifier
98 if p.nth(1).as_str() == "property"
99 && matches!(
100 p.peek().as_str(),
101 "in" | "out" | "in_out" | "in-out" | "private"
102 ) =>
103 {
104 parse_property_declaration(&mut *p);
105 }
106 _ if p.peek().as_str() == "if" => {
107 parse_if_element(&mut *p);
108 }
109 SyntaxKind::LBracket if p.peek().as_str() == "states" => {
110 parse_states(&mut *p);
111 }
112 SyntaxKind::LBracket if p.peek().as_str() == "transitions" => {
113 parse_transitions(&mut *p);
114 }
115 _ => {
116 if p.peek().as_str() == "changed" {
117 parse_changed_callback(&mut *p);
119 } else {
120 p.consume();
121 if !had_parse_error {
122 p.error("Parse error");
123 had_parse_error = true;
124 }
125 }
126 }
127 },
128 SyntaxKind::At => {
129 let checkpoint = p.checkpoint();
130 p.consume();
131 if p.peek().as_str() == "children" {
132 let mut p =
133 p.start_node_at(checkpoint.clone(), SyntaxKind::ChildrenPlaceholder);
134 p.consume()
135 } else {
136 p.test(SyntaxKind::Identifier);
137 p.error("Parse error: Expected @children")
138 }
139 }
140 _ => {
141 if !had_parse_error {
142 p.error("Parse error");
143 had_parse_error = true;
144 }
145 p.consume();
146 }
147 }
148 }
149}
150
151#[cfg_attr(test, parser_test)]
152fn parse_sub_element(p: &mut impl Parser) -> bool {
159 let mut p = p.start_node(SyntaxKind::SubElement);
160 if p.nth(1).kind() == SyntaxKind::ColonEqual {
161 p.expect(SyntaxKind::Identifier);
162 p.expect(SyntaxKind::ColonEqual);
163 }
164 parse_element(&mut *p)
165}
166
167#[cfg_attr(test, parser_test)]
168fn parse_repeated_element(p: &mut impl Parser) {
176 debug_assert_eq!(p.peek().as_str(), "for");
177 let mut p = p.start_node(SyntaxKind::RepeatedElement);
178 p.expect(SyntaxKind::Identifier); if p.nth(0).kind() == SyntaxKind::Identifier {
180 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
181 p.expect(SyntaxKind::Identifier);
182 }
183 if p.nth(0).kind() == SyntaxKind::LBracket {
184 let mut p = p.start_node(SyntaxKind::RepeatedIndex);
185 p.expect(SyntaxKind::LBracket);
186 p.expect(SyntaxKind::Identifier);
187 p.expect(SyntaxKind::RBracket);
188 }
189 if p.peek().as_str() != "in" {
190 p.error("Invalid 'for' syntax: there should be a 'in' token");
191 drop(p.start_node(SyntaxKind::Expression));
192 drop(p.start_node(SyntaxKind::SubElement).start_node(SyntaxKind::Element));
193 return;
194 }
195 p.consume(); parse_expression(&mut *p);
197 p.expect(SyntaxKind::Colon);
198 parse_sub_element(&mut *p);
199}
200
201#[cfg_attr(test, parser_test)]
202fn parse_if_element(p: &mut impl Parser) {
210 debug_assert_eq!(p.peek().as_str(), "if");
211 let mut p = p.start_node(SyntaxKind::ConditionalElement);
212 p.expect(SyntaxKind::Identifier); parse_expression(&mut *p);
214 if !p.expect(SyntaxKind::Colon) {
215 drop(p.start_node(SyntaxKind::SubElement).start_node(SyntaxKind::Element));
216 return;
217 }
218 parse_sub_element(&mut *p);
219}
220
221#[cfg_attr(test, parser_test)]
222fn parse_property_binding(p: &mut impl Parser) {
227 let mut p = p.start_node(SyntaxKind::Binding);
228 p.consume();
229 p.expect(SyntaxKind::Colon);
230 parse_binding_expression(&mut *p);
231}
232
233#[cfg_attr(test, parser_test)]
234fn parse_binding_expression(p: &mut impl Parser) -> bool {
241 let mut p = p.start_node(SyntaxKind::BindingExpression);
242 if p.nth(0).kind() == SyntaxKind::LBrace && p.nth(2).kind() != SyntaxKind::Colon {
243 parse_code_block(&mut *p);
244 p.test(SyntaxKind::Semicolon);
245 true
246 } else if parse_expression(&mut *p) {
247 p.expect(SyntaxKind::Semicolon)
248 } else {
249 p.test(SyntaxKind::Semicolon);
250 false
251 }
252}
253
254#[cfg_attr(test, parser_test)]
255pub fn parse_code_block(p: &mut impl Parser) {
263 let mut p = p.start_node(SyntaxKind::CodeBlock);
264 p.expect(SyntaxKind::LBrace); while p.nth(0).kind() != SyntaxKind::RBrace {
267 if !parse_statement(&mut *p) {
268 break;
269 }
270 }
271 p.expect(SyntaxKind::RBrace);
272}
273
274#[cfg_attr(test, parser_test)]
275fn parse_callback_connection(p: &mut impl Parser) {
284 let mut p = p.start_node(SyntaxKind::CallbackConnection);
285 p.consume(); if p.test(SyntaxKind::LParent) {
287 while p.peek().kind() != SyntaxKind::RParent {
288 {
289 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
290 p.expect(SyntaxKind::Identifier);
291 }
292 if !p.test(SyntaxKind::Comma) {
293 break;
294 }
295 }
296 p.expect(SyntaxKind::RParent);
297 }
298 p.expect(SyntaxKind::FatArrow);
299 if p.nth(0).kind() == SyntaxKind::LBrace && p.nth(2).kind() != SyntaxKind::Colon {
300 parse_code_block(&mut *p);
301 p.test(SyntaxKind::Semicolon);
302 } else if parse_expression(&mut *p) {
303 p.expect(SyntaxKind::Semicolon);
304 } else {
305 p.test(SyntaxKind::Semicolon);
306 }
307}
308
309#[cfg_attr(test, parser_test)]
310fn parse_two_way_binding(p: &mut impl Parser) {
315 let mut p = p.start_node(SyntaxKind::TwoWayBinding);
316 p.consume(); p.expect(SyntaxKind::DoubleArrow);
318 parse_expression(&mut *p);
319 p.expect(SyntaxKind::Semicolon);
320}
321
322#[cfg_attr(test, parser_test)]
323fn parse_callback_declaration(p: &mut impl Parser) {
336 let mut p = p.start_node(SyntaxKind::CallbackDeclaration);
337 if p.peek().as_str() == "pure" {
338 p.consume();
339 }
340 debug_assert_eq!(p.peek().as_str(), "callback");
341 p.expect(SyntaxKind::Identifier); {
343 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
344 p.expect(SyntaxKind::Identifier);
345 }
346 if p.test(SyntaxKind::LParent) {
347 while p.peek().kind() != SyntaxKind::RParent {
348 {
349 let mut p = p.start_node(SyntaxKind::CallbackDeclarationParameter);
350 if p.peek().kind() == SyntaxKind::Identifier && p.nth(1).kind() == SyntaxKind::Colon
351 {
352 {
353 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
354 p.expect(SyntaxKind::Identifier);
355 }
356 p.expect(SyntaxKind::Colon);
357 }
358 parse_type(&mut *p);
359 }
360 if !p.test(SyntaxKind::Comma) {
361 break;
362 }
363 }
364 p.expect(SyntaxKind::RParent);
365 if p.test(SyntaxKind::Arrow) {
366 let mut p = p.start_node(SyntaxKind::ReturnType);
367 parse_type(&mut *p);
368 }
369
370 if p.peek().kind() == SyntaxKind::DoubleArrow {
371 p.error("When declaring a callback alias, one must omit parentheses. e.g. 'callback foo <=> other.bar;'");
372 }
373 } else if p.test(SyntaxKind::Arrow) {
374 p.error("Callback with return value must be declared with parentheses e.g. 'callback foo() -> int;'");
377 parse_type(&mut *p);
378 }
379
380 if p.peek().kind() == SyntaxKind::DoubleArrow {
381 let mut p = p.start_node(SyntaxKind::TwoWayBinding);
382 p.expect(SyntaxKind::DoubleArrow);
383 parse_expression(&mut *p);
384 }
385
386 p.expect(SyntaxKind::Semicolon);
387}
388
389#[cfg_attr(test, parser_test)]
390fn parse_property_declaration(p: &mut impl Parser) {
398 let checkpoint = p.checkpoint();
399 while matches!(p.peek().as_str(), "in" | "out" | "in-out" | "in_out" | "private") {
400 p.consume();
401 }
402 if p.peek().as_str() != "property" {
403 p.error("Expected 'property' keyword");
404 return;
405 }
406 let mut p = p.start_node_at(checkpoint, SyntaxKind::PropertyDeclaration);
407 p.consume(); if p.test(SyntaxKind::LAngle) {
410 parse_type(&mut *p);
411 p.expect(SyntaxKind::RAngle);
412 } else if p.nth(0).kind() == SyntaxKind::Identifier
413 && p.nth(1).kind() != SyntaxKind::DoubleArrow
414 {
415 p.error("Missing type. The syntax to declare a property is `property <type> name;`. Only two way bindings can omit the type");
416 }
417
418 {
419 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
420 p.expect(SyntaxKind::Identifier);
421 }
422
423 match p.nth(0).kind() {
424 SyntaxKind::Colon => {
425 p.consume();
426 parse_binding_expression(&mut *p);
427 }
428 SyntaxKind::DoubleArrow => {
429 let mut p = p.start_node(SyntaxKind::TwoWayBinding);
430 p.consume();
431 parse_expression(&mut *p);
432 p.expect(SyntaxKind::Semicolon);
433 }
434 _ => {
435 p.expect(SyntaxKind::Semicolon);
436 }
437 }
438}
439
440#[cfg_attr(test, parser_test)]
441fn parse_property_animation(p: &mut impl Parser) {
447 debug_assert_eq!(p.peek().as_str(), "animate");
448 let mut p = p.start_node(SyntaxKind::PropertyAnimation);
449 p.expect(SyntaxKind::Identifier); if p.nth(0).kind() == SyntaxKind::Star {
451 p.consume();
452 } else {
453 parse_qualified_name(&mut *p);
454 while p.nth(0).kind() == SyntaxKind::Comma {
455 p.consume();
456 parse_qualified_name(&mut *p);
457 }
458 };
459 p.expect(SyntaxKind::LBrace);
460
461 loop {
462 match p.nth(0).kind() {
463 SyntaxKind::RBrace => {
464 p.consume();
465 return;
466 }
467 SyntaxKind::Eof => return,
468 SyntaxKind::Identifier => match p.nth(1).kind() {
469 SyntaxKind::Colon => parse_property_binding(&mut *p),
470 _ => {
471 p.consume();
472 p.error("Only bindings are allowed in animations");
473 }
474 },
475 _ => {
476 p.consume();
477 p.error("Only bindings are allowed in animations");
478 }
479 }
480 }
481}
482
483#[cfg_attr(test, parser_test)]
484fn parse_changed_callback(p: &mut impl Parser) {
490 debug_assert_eq!(p.peek().as_str(), "changed");
491 let mut p = p.start_node(SyntaxKind::PropertyChangedCallback);
492 p.expect(SyntaxKind::Identifier); {
494 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
495 p.expect(SyntaxKind::Identifier);
496 }
497 p.expect(SyntaxKind::FatArrow);
498
499 if p.nth(0).kind() == SyntaxKind::LBrace && p.nth(2).kind() != SyntaxKind::Colon {
500 parse_code_block(&mut *p);
501 p.test(SyntaxKind::Semicolon);
502 } else if parse_expression(&mut *p) {
503 p.expect(SyntaxKind::Semicolon);
504 } else {
505 p.test(SyntaxKind::Semicolon);
506 }
507}
508
509#[cfg_attr(test, parser_test)]
510fn parse_states(p: &mut impl Parser) {
515 debug_assert_eq!(p.peek().as_str(), "states");
516 let mut p = p.start_node(SyntaxKind::States);
517 p.expect(SyntaxKind::Identifier); p.expect(SyntaxKind::LBracket);
519 while parse_state(&mut *p) {}
520 p.expect(SyntaxKind::RBracket);
521}
522
523#[cfg_attr(test, parser_test)]
524fn parse_state(p: &mut impl Parser) -> bool {
531 if p.nth(0).kind() != SyntaxKind::Identifier {
532 return false;
533 }
534 let mut p = p.start_node(SyntaxKind::State);
535 {
536 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
537 p.expect(SyntaxKind::Identifier);
538 }
539 if p.peek().as_str() == "when" {
540 p.consume();
541 parse_expression(&mut *p);
542 }
543 p.expect(SyntaxKind::Colon);
544 if !p.expect(SyntaxKind::LBrace) {
545 return false;
546 }
547
548 loop {
549 match p.nth(0).kind() {
550 SyntaxKind::RBrace => {
551 p.consume();
552 return true;
553 }
554 SyntaxKind::Eof => return false,
555 _ => {
556 if p.nth(1).kind() == SyntaxKind::LBrace
557 && matches!(p.peek().as_str(), "in" | "out" | "in-out" | "in_out")
558 {
559 let mut p = p.start_node(SyntaxKind::Transition);
560 p.consume(); p.expect(SyntaxKind::LBrace);
562 if !parse_transition_inner(&mut *p) {
563 return false;
564 }
565 continue;
566 };
567 let checkpoint = p.checkpoint();
568 if !parse_qualified_name(&mut *p)
569 || !p.expect(SyntaxKind::Colon)
570 || !parse_binding_expression(&mut *p)
571 {
572 p.test(SyntaxKind::RBrace);
573 return false;
574 }
575 let _ = p.start_node_at(checkpoint, SyntaxKind::StatePropertyChange);
576 }
577 }
578 }
579}
580
581#[cfg_attr(test, parser_test)]
582fn parse_transitions(p: &mut impl Parser) {
587 debug_assert_eq!(p.peek().as_str(), "transitions");
588 let mut p = p.start_node(SyntaxKind::Transitions);
589 p.expect(SyntaxKind::Identifier); p.expect(SyntaxKind::LBracket);
591 while p.nth(0).kind() != SyntaxKind::RBracket && parse_transition(&mut *p) {}
592 p.expect(SyntaxKind::RBracket);
593}
594
595#[cfg_attr(test, parser_test)]
596fn parse_transition(p: &mut impl Parser) -> bool {
603 if !matches!(p.peek().as_str(), "in" | "out" | "in-out" | "in_out") {
604 p.error("Expected 'in', 'out', or 'in-out' to declare a transition");
605 return false;
606 }
607 let mut p = p.start_node(SyntaxKind::Transition);
608 p.consume(); {
610 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
611 p.expect(SyntaxKind::Identifier);
612 }
613 p.expect(SyntaxKind::Colon);
614 if !p.expect(SyntaxKind::LBrace) {
615 return false;
616 }
617 parse_transition_inner(&mut *p)
618}
619
620#[cfg_attr(test, parser_test)]
621fn parse_transition_inner(p: &mut impl Parser) -> bool {
626 loop {
627 match p.nth(0).kind() {
628 SyntaxKind::RBrace => {
629 p.consume();
630 return true;
631 }
632 SyntaxKind::Eof => return false,
633 SyntaxKind::Identifier if p.peek().as_str() == "animate" => {
634 parse_property_animation(&mut *p);
635 }
636 _ => {
637 p.consume();
638 p.error("Expected 'animate'");
639 }
640 }
641 }
642}
643
644#[cfg_attr(test, parser_test)]
645fn parse_function(p: &mut impl Parser) {
653 let mut p = p.start_node(SyntaxKind::Function);
654 if matches!(p.peek().as_str(), "public" | "protected") {
655 p.consume();
656 if p.peek().as_str() == "pure" {
657 p.consume()
658 }
659 } else if p.peek().as_str() == "pure" {
660 p.consume();
661 if matches!(p.peek().as_str(), "public" | "protected") {
662 p.consume()
663 }
664 }
665 if p.peek().as_str() != "function" {
666 p.error("Unexpected identifier");
667 p.consume();
668 while p.peek().kind == SyntaxKind::Identifier && p.peek().as_str() != "function" {
669 p.consume();
670 }
671 }
672 debug_assert_eq!(p.peek().as_str(), "function");
673 p.expect(SyntaxKind::Identifier); {
675 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
676 p.expect(SyntaxKind::Identifier);
677 }
678 if p.expect(SyntaxKind::LParent) {
679 while p.peek().kind() != SyntaxKind::RParent {
680 let mut p_arg = p.start_node(SyntaxKind::ArgumentDeclaration);
681 {
682 let mut p = p_arg.start_node(SyntaxKind::DeclaredIdentifier);
683 p.expect(SyntaxKind::Identifier);
684 }
685 p_arg.expect(SyntaxKind::Colon);
686 parse_type(&mut *p_arg);
687 drop(p_arg);
688 if !p.test(SyntaxKind::Comma) {
689 break;
690 }
691 }
692 p.expect(SyntaxKind::RParent);
693 if p.test(SyntaxKind::Arrow) {
694 let mut p = p.start_node(SyntaxKind::ReturnType);
695 parse_type(&mut *p);
696 }
697 }
698 parse_code_block(&mut *p);
699}