1use super::document::parse_qualified_name;
7use super::expressions::parse_expression;
8use super::prelude::*;
9use super::statements::parse_statement;
10use super::r#type::parse_type;
11
12#[cfg_attr(test, parser_test)]
13pub fn parse_element(p: &mut impl Parser) -> bool {
20 let mut p = p.start_node(SyntaxKind::Element);
21 if !parse_qualified_name(&mut *p) {
22 return if p.test(SyntaxKind::LBrace) {
23 parse_element_content(&mut *p);
25 p.expect(SyntaxKind::RBrace)
26 } else {
27 false
28 };
29 }
30
31 if !p.expect(SyntaxKind::LBrace) {
32 return false;
33 }
34
35 parse_element_content(&mut *p);
36
37 p.expect(SyntaxKind::RBrace)
38}
39
40#[cfg_attr(test, parser_test)]
41pub fn parse_element_content(p: &mut impl Parser) {
67 let mut had_parse_error = false;
68 loop {
69 match p.nth(0).kind() {
70 SyntaxKind::RBrace => return,
71 SyntaxKind::Eof => return,
72 SyntaxKind::Identifier => match p.nth(1).kind() {
73 SyntaxKind::Identifier | SyntaxKind::Semicolon if p.peek().as_str() == "slot" => {
74 parse_slot_declaration(&mut *p)
75 }
76 SyntaxKind::Colon => parse_property_binding(&mut *p),
77 SyntaxKind::DoubleLess => {
78 had_parse_error |= !parse_slot_assignment_or_forwarding(&mut *p)
79 }
80 SyntaxKind::ColonEqual | SyntaxKind::LBrace => {
81 had_parse_error |= !parse_sub_element(&mut *p);
82 }
83 SyntaxKind::FatArrow | SyntaxKind::LParent
84 if !["if", "match"].contains(&p.peek().as_str()) =>
85 {
86 parse_callback_connection(&mut *p)
87 }
88 SyntaxKind::DoubleArrow => parse_two_way_binding(&mut *p),
89 SyntaxKind::Identifier if p.peek().as_str() == "for" => {
90 parse_repeated_element(&mut *p);
91 }
92 SyntaxKind::Identifier
93 if p.peek().as_str() == "callback"
94 || (p.peek().as_str() == "pure" && p.nth(1).as_str() == "callback") =>
95 {
96 parse_callback_declaration(&mut *p, None);
97 }
98 SyntaxKind::Identifier
99 if p.peek().as_str() == "function"
100 || (matches!(p.peek().as_str(), "public" | "pure" | "protected")
101 && p.nth(1).as_str() == "function")
102 || (matches!(p.nth(1).as_str(), "public" | "pure" | "protected")
103 && p.nth(2).as_str() == "function") =>
104 {
105 parse_function(&mut *p, None);
106 }
107 SyntaxKind::Identifier | SyntaxKind::Star if p.peek().as_str() == "animate" => {
108 parse_property_animation(&mut *p);
109 }
110 SyntaxKind::Identifier if p.peek().as_str() == "changed" => {
111 parse_changed_callback(&mut *p);
112 }
113 SyntaxKind::LAngle | SyntaxKind::Identifier if p.peek().as_str() == "property" => {
114 parse_property_declaration(&mut *p, None);
115 }
116 SyntaxKind::Identifier
117 if p.nth(1).as_str() == "property"
118 && matches!(
119 p.peek().as_str(),
120 "in" | "out" | "in_out" | "in-out" | "private"
121 ) =>
122 {
123 parse_property_declaration(&mut *p, None);
124 }
125 _ if p.peek().as_str() == "if" => {
126 parse_if_element(&mut *p);
127 }
128 SyntaxKind::Identifier | SyntaxKind::LParent if p.peek().as_str() == "match" => {
129 let mut i = 2;
130 loop {
131 match p.nth(i).kind() {
132 SyntaxKind::FatArrow => {
133 parse_callback_connection(&mut *p);
134 break;
135 }
136 SyntaxKind::LBrace => {
137 parse_match_element(&mut *p);
138 break;
139 }
140 SyntaxKind::Eof => {
141 if !had_parse_error {
142 p.error("Error: Expected '{'");
143 had_parse_error = true;
144 }
145 break;
146 }
147 _ => i += 1,
148 }
149 }
150 }
151 SyntaxKind::LBracket if p.peek().as_str() == "states" => {
152 parse_states(&mut *p);
153 }
154 SyntaxKind::LBracket if p.peek().as_str() == "transitions" => {
155 parse_transitions(&mut *p);
156 }
157 SyntaxKind::Identifier if p.peek().as_str() == "implement" => {
158 parse_implement_statement(&mut *p);
159 }
160 _ => {
161 if p.peek().as_str() == "changed" {
162 parse_changed_callback(&mut *p);
164 } else {
165 p.consume();
166 if !had_parse_error {
167 p.error("Parse error");
168 had_parse_error = true;
169 }
170 }
171 }
172 },
173 SyntaxKind::At => {
174 if matches!(p.nth(1).as_str(), "deprecated" | "shadowable") {
175 let checkpoint = p.checkpoint();
176 let attribute = parse_member_attributes(&mut *p);
177 let mut i = 0;
179 while matches!(
180 p.nth(i).as_str(),
181 "in" | "out"
182 | "in-out"
183 | "in_out"
184 | "private"
185 | "public"
186 | "protected"
187 | "pure"
188 ) {
189 i += 1;
190 }
191 match p.nth(i).as_str() {
192 "callback" => parse_callback_declaration(&mut *p, Some(checkpoint)),
193 "function" => parse_function(&mut *p, Some(checkpoint)),
194 "property" => parse_property_declaration(&mut *p, Some(checkpoint)),
195 _ => {
196 (0..i).for_each(|_| p.consume());
197 if let Some(attribute) = attribute {
198 p.error(format!(
199 "@{attribute} can only be applied to a member declaration"
200 ));
201 }
202 }
203 }
204 continue;
205 }
206 let checkpoint = p.checkpoint();
207 p.consume();
208 if p.peek().as_str() == "children" {
209 let mut p =
210 p.start_node_at(checkpoint.clone(), SyntaxKind::ChildrenPlaceholder);
211 p.consume()
212 } else {
213 p.test(SyntaxKind::Identifier);
214 p.error("Parse error: Expected @children")
215 }
216 }
217 _ => {
218 if !had_parse_error {
219 p.error("Parse error");
220 had_parse_error = true;
221 }
222 p.consume();
223 }
224 }
225 }
226}
227
228#[cfg_attr(test, parser_test)]
229fn parse_sub_element(p: &mut impl Parser) -> bool {
236 let mut p = p.start_node(SyntaxKind::SubElement);
237 if p.nth(1).kind() == SyntaxKind::ColonEqual {
238 p.expect(SyntaxKind::Identifier);
239 p.expect(SyntaxKind::ColonEqual);
240 }
241 parse_element(&mut *p)
242}
243
244#[cfg_attr(test, parser_test)]
245fn parse_slot_declaration(p: &mut impl Parser) {
249 debug_assert_eq!(p.peek().as_str(), "slot");
250 let mut p = p.start_node(SyntaxKind::SlotDeclaration);
251 p.expect(SyntaxKind::Identifier); {
253 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
254 p.expect(SyntaxKind::Identifier);
255 }
256 p.expect(SyntaxKind::Semicolon);
257}
258
259#[cfg_attr(test, parser_test)]
260fn parse_slot_assignment(p: &mut impl Parser) -> bool {
264 let mut p = p.start_node(SyntaxKind::SlotAssignment);
265 {
266 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
267 p.expect(SyntaxKind::Identifier);
268 }
269 p.expect(SyntaxKind::DoubleLess);
270 if !parse_sub_element(&mut *p) {
271 p.error("Expected element after '<<'");
272 return false;
273 }
274 true
275}
276
277#[cfg_attr(test, parser_test)]
278fn parse_slot_forwarding(p: &mut impl Parser) -> bool {
283 let mut p = p.start_node(SyntaxKind::SlotForwarding);
284 {
285 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
286 p.expect(SyntaxKind::Identifier);
287 }
288 p.expect(SyntaxKind::DoubleLess);
289 if !parse_expression(&mut *p) {
290 return false;
291 }
292 p.expect(SyntaxKind::Semicolon)
293}
294
295fn parse_slot_assignment_or_forwarding(p: &mut impl Parser) -> bool {
296 debug_assert_eq!(p.nth(1).kind(), SyntaxKind::DoubleLess);
297 let rhs_first = p.nth(2).kind();
298 let rhs_second = p.nth(3).kind();
299
300 let is_slot_assignment = rhs_first == SyntaxKind::Identifier
301 && matches!(rhs_second, SyntaxKind::LBrace | SyntaxKind::ColonEqual);
302
303 if is_slot_assignment { parse_slot_assignment(p) } else { parse_slot_forwarding(p) }
304}
305
306#[cfg_attr(test, parser_test)]
307fn parse_repeated_element(p: &mut impl Parser) {
315 debug_assert_eq!(p.peek().as_str(), "for");
316 let mut p = p.start_node(SyntaxKind::RepeatedElement);
317 p.expect(SyntaxKind::Identifier); if p.nth(0).kind() == SyntaxKind::Identifier {
319 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
320 p.expect(SyntaxKind::Identifier);
321 }
322 if p.nth(0).kind() == SyntaxKind::LBracket {
323 let mut p = p.start_node(SyntaxKind::RepeatedIndex);
324 p.expect(SyntaxKind::LBracket);
325 p.expect(SyntaxKind::Identifier);
326 p.expect(SyntaxKind::RBracket);
327 }
328 if p.peek().as_str() != "in" {
329 p.error("Invalid 'for' syntax: there should be a 'in' token");
330 drop(p.start_node(SyntaxKind::Expression));
331 drop(p.start_node(SyntaxKind::SubElement).start_node(SyntaxKind::Element));
332 return;
333 }
334 p.consume(); parse_expression(&mut *p);
336 p.expect(SyntaxKind::Colon);
337 parse_sub_element(&mut *p);
338}
339
340#[cfg_attr(test, parser_test)]
341fn parse_if_element(p: &mut impl Parser) {
349 debug_assert_eq!(p.peek().as_str(), "if");
350 let mut p = p.start_node(SyntaxKind::ConditionalElement);
351 p.expect(SyntaxKind::Identifier); parse_expression(&mut *p);
353 if !p.expect(SyntaxKind::Colon) {
354 drop(p.start_node(SyntaxKind::SubElement).start_node(SyntaxKind::Element));
355 return;
356 }
357 parse_sub_element(&mut *p);
358}
359
360#[cfg_attr(test, parser_test)]
361fn parse_match_element(p: &mut impl Parser) {
367 debug_assert_eq!(p.peek().as_str(), "match");
368 let mut p = p.start_node(SyntaxKind::MatchElement);
369 p.expect(SyntaxKind::Identifier); parse_expression(&mut *p);
371 if !p.test(SyntaxKind::LBrace) {
372 p.error("Expected '{' to start cases");
373 }
374 while ![SyntaxKind::RBrace, SyntaxKind::Star, SyntaxKind::Eof].contains(&p.peek().kind()) {
375 parse_match_case(&mut *p);
376 }
377 if p.peek().kind() == SyntaxKind::Star {
378 parse_wildcard_case(&mut *p);
379 let mut reported = false;
380 while p.peek().kind() == SyntaxKind::Star
381 || (![SyntaxKind::RBrace, SyntaxKind::Eof].contains(&p.peek().kind())
382 && p.nth(1).kind() == SyntaxKind::Colon)
383 {
384 if !reported {
385 p.error("Cases after the '*' case are never hit");
386 reported = true;
387 }
388 if p.peek().kind() == SyntaxKind::Star {
389 parse_wildcard_case(&mut *p);
390 } else {
391 parse_match_case(&mut *p);
392 }
393 }
394 }
395 p.expect(SyntaxKind::RBrace);
396}
397
398#[cfg_attr(test, parser_test)]
399fn parse_match_case(p: &mut impl Parser) {
405 let mut p = p.start_node(SyntaxKind::MatchCase);
406 parse_expression(&mut *p);
407 parse_case_inner(&mut *p, "match case");
408}
409
410#[cfg_attr(test, parser_test)]
411fn parse_wildcard_case(p: &mut impl Parser) {
415 debug_assert_eq!(p.peek().kind(), SyntaxKind::Star);
416 let mut p = p.start_node(SyntaxKind::WildcardMatchCase);
417 p.expect(SyntaxKind::Star);
418 parse_case_inner(&mut *p, "'*'");
419}
420
421fn parse_case_inner(p: &mut impl Parser, after: &str) {
422 if !p.test(SyntaxKind::Colon) {
423 p.error(format!("Expected ':' after {after}"));
424 if p.peek().kind() != SyntaxKind::Identifier {
425 p.consume();
426 }
427 }
428 if p.peek().kind() == SyntaxKind::LBrace {
429 p.expect(SyntaxKind::LBrace);
431 if p.peek().kind() == SyntaxKind::Identifier {
432 p.error("Remove '{ }' around case element");
433 parse_sub_element(&mut *p);
434 }
435 p.expect(SyntaxKind::RBrace);
436 return;
437 }
438 parse_sub_element(&mut *p);
439}
440
441#[cfg_attr(test, parser_test)]
442fn parse_property_binding(p: &mut impl Parser) {
447 let mut p = p.start_node(SyntaxKind::Binding);
448 p.consume();
449 p.expect(SyntaxKind::Colon);
450 parse_binding_expression(&mut *p);
451}
452
453#[cfg_attr(test, parser_test)]
454fn parse_binding_expression(p: &mut impl Parser) -> bool {
461 let mut p = p.start_node(SyntaxKind::BindingExpression);
462 if p.nth(0).kind() == SyntaxKind::LBrace && p.nth(2).kind() != SyntaxKind::Colon {
463 parse_code_block(&mut *p);
464 p.test(SyntaxKind::Semicolon);
465 true
466 } else if parse_expression(&mut *p) {
467 p.expect(SyntaxKind::Semicolon)
468 } else {
469 p.test(SyntaxKind::Semicolon);
470 false
471 }
472}
473
474#[cfg_attr(test, parser_test)]
475pub fn parse_code_block(p: &mut impl Parser) {
483 let mut p = p.start_node(SyntaxKind::CodeBlock);
484 p.expect(SyntaxKind::LBrace); while p.nth(0).kind() != SyntaxKind::RBrace {
487 if !parse_statement(&mut *p) {
488 break;
489 }
490 }
491 p.expect(SyntaxKind::RBrace);
492}
493
494#[cfg_attr(test, parser_test)]
495fn parse_callback_connection(p: &mut impl Parser) {
504 let mut p = p.start_node(SyntaxKind::CallbackConnection);
505 p.consume(); if p.test(SyntaxKind::LParent) {
507 while p.peek().kind() != SyntaxKind::RParent {
508 {
509 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
510 p.expect(SyntaxKind::Identifier);
511 }
512 if !p.test(SyntaxKind::Comma) {
513 break;
514 }
515 }
516 p.expect(SyntaxKind::RParent);
517 }
518 p.expect(SyntaxKind::FatArrow);
519 if p.nth(0).kind() == SyntaxKind::LBrace && p.nth(2).kind() != SyntaxKind::Colon {
520 parse_code_block(&mut *p);
521 p.test(SyntaxKind::Semicolon);
522 } else if parse_expression(&mut *p) {
523 p.expect(SyntaxKind::Semicolon);
524 } else {
525 p.test(SyntaxKind::Semicolon);
526 }
527}
528
529#[cfg_attr(test, parser_test)]
530fn parse_two_way_binding(p: &mut impl Parser) {
535 let mut p = p.start_node(SyntaxKind::TwoWayBinding);
536 p.consume(); p.expect(SyntaxKind::DoubleArrow);
538 parse_expression(&mut *p);
539 p.expect(SyntaxKind::Semicolon);
540}
541
542#[cfg_attr(test, parser_test)]
543fn parse_implement_statement(p: &mut impl Parser) {
551 debug_assert_eq!(p.peek().as_str(), "implement");
552 let mut p = p.start_node(SyntaxKind::ImplementStatement);
553 p.expect(SyntaxKind::Identifier); parse_qualified_name(&mut *p);
555 p.expect(SyntaxKind::DoubleArrow);
556 {
557 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
558 p.expect(SyntaxKind::Identifier);
559 }
560 p.expect(SyntaxKind::Semicolon);
561}
562
563#[cfg_attr(test, parser_test)]
564fn parse_callback_declaration<P: Parser>(p: &mut P, checkpoint: Option<P::Checkpoint>) {
577 let checkpoint = checkpoint.unwrap_or_else(|| p.checkpoint());
578 let mut p = p.start_node_at(checkpoint, SyntaxKind::CallbackDeclaration);
579 if p.peek().as_str() == "pure" {
580 p.consume();
581 }
582 debug_assert_eq!(p.peek().as_str(), "callback");
583 p.expect(SyntaxKind::Identifier); {
585 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
586 p.expect(SyntaxKind::Identifier);
587 }
588 if p.test(SyntaxKind::LParent) {
589 while p.peek().kind() != SyntaxKind::RParent {
590 {
591 let mut p = p.start_node(SyntaxKind::CallbackDeclarationParameter);
592 if p.peek().kind() == SyntaxKind::Identifier && p.nth(1).kind() == SyntaxKind::Colon
593 {
594 {
595 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
596 p.expect(SyntaxKind::Identifier);
597 }
598 p.expect(SyntaxKind::Colon);
599 }
600 parse_type(&mut *p);
601 }
602 if !p.test(SyntaxKind::Comma) {
603 break;
604 }
605 }
606 p.expect(SyntaxKind::RParent);
607 if p.test(SyntaxKind::Arrow) {
608 let mut p = p.start_node(SyntaxKind::ReturnType);
609 parse_type(&mut *p);
610 }
611
612 if p.peek().kind() == SyntaxKind::DoubleArrow {
613 p.error("When declaring a callback alias, one must omit parentheses. e.g. 'callback foo <=> other.bar;'");
614 }
615 } else if p.test(SyntaxKind::Arrow) {
616 p.error("Callback with return value must be declared with parentheses e.g. 'callback foo() -> int;'");
619 parse_type(&mut *p);
620 }
621
622 if p.peek().kind() == SyntaxKind::DoubleArrow {
623 let mut p = p.start_node(SyntaxKind::TwoWayBinding);
624 p.expect(SyntaxKind::DoubleArrow);
625 parse_expression(&mut *p);
626 }
627
628 p.expect(SyntaxKind::Semicolon);
629}
630
631#[cfg_attr(test, parser_test)]
632fn parse_member_attributes(p: &mut impl Parser) -> Option<&'static str> {
638 let mut seen: Vec<&'static str> = Vec::new();
639 while p.nth(0).kind() == SyntaxKind::At
640 && matches!(p.nth(1).as_str(), "deprecated" | "shadowable")
641 {
642 let is_deprecated = p.nth(1).as_str() == "deprecated";
643 let (name, kind) = if is_deprecated {
644 ("deprecated", SyntaxKind::PropertyDeprecation)
645 } else {
646 ("shadowable", SyntaxKind::ShadowableAttribute)
647 };
648 let duplicated = seen.contains(&name);
649 seen.push(name);
650 let mut p = p.start_node(kind);
651 p.consume(); p.consume(); if duplicated {
654 p.error(format!("Duplicated @{name} attribute"));
655 }
656 if is_deprecated && p.test(SyntaxKind::LParent) {
657 let peek = p.peek();
658 if peek.kind() != SyntaxKind::StringLiteral
659 || !peek.as_str().starts_with('"')
660 || !peek.as_str().ends_with('"')
661 {
662 p.error("@deprecated message must be a plain string literal, without any '\\{}' expressions");
663 p.until(SyntaxKind::RParent);
664 } else {
665 p.expect(SyntaxKind::StringLiteral);
666 p.expect(SyntaxKind::RParent);
667 }
668 }
669 }
670 seen.first().copied()
671}
672
673#[cfg_attr(test, parser_test)]
674fn parse_property_declaration<P: Parser>(p: &mut P, checkpoint: Option<P::Checkpoint>) {
682 let checkpoint = checkpoint.unwrap_or_else(|| p.checkpoint());
683 while matches!(p.peek().as_str(), "in" | "out" | "in-out" | "in_out" | "private") {
684 p.consume();
685 }
686 if p.peek().as_str() != "property" {
687 p.error("Expected 'property' keyword");
688 return;
689 }
690 let mut p = p.start_node_at(checkpoint, SyntaxKind::PropertyDeclaration);
691 p.consume(); if p.test(SyntaxKind::LAngle) {
694 parse_type(&mut *p);
695 p.expect(SyntaxKind::RAngle);
696 } else if p.nth(0).kind() == SyntaxKind::Identifier
697 && p.nth(1).kind() != SyntaxKind::DoubleArrow
698 {
699 p.error("Missing type. The syntax to declare a property is `property <type> name;`. Only two way bindings can omit the type");
700 }
701
702 {
703 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
704 p.expect(SyntaxKind::Identifier);
705 }
706
707 match p.nth(0).kind() {
708 SyntaxKind::Colon => {
709 p.consume();
710 parse_binding_expression(&mut *p);
711 }
712 SyntaxKind::DoubleArrow => {
713 let mut p = p.start_node(SyntaxKind::TwoWayBinding);
714 p.consume();
715 parse_expression(&mut *p);
716 p.expect(SyntaxKind::Semicolon);
717 }
718 _ => {
719 p.expect(SyntaxKind::Semicolon);
720 }
721 }
722}
723
724#[cfg_attr(test, parser_test)]
725fn parse_property_animation(p: &mut impl Parser) {
731 debug_assert_eq!(p.peek().as_str(), "animate");
732 let mut p = p.start_node(SyntaxKind::PropertyAnimation);
733 p.expect(SyntaxKind::Identifier); if p.nth(0).kind() == SyntaxKind::Star {
735 p.consume();
736 } else {
737 parse_qualified_name(&mut *p);
738 while p.nth(0).kind() == SyntaxKind::Comma {
739 p.consume();
740 parse_qualified_name(&mut *p);
741 }
742 };
743 p.expect(SyntaxKind::LBrace);
744
745 loop {
746 match p.nth(0).kind() {
747 SyntaxKind::RBrace => {
748 p.consume();
749 return;
750 }
751 SyntaxKind::Eof => return,
752 SyntaxKind::Identifier => match p.nth(1).kind() {
753 SyntaxKind::Colon => parse_property_binding(&mut *p),
754 _ => {
755 p.consume();
756 p.error("Only bindings are allowed in animations");
757 }
758 },
759 _ => {
760 p.consume();
761 p.error("Only bindings are allowed in animations");
762 }
763 }
764 }
765}
766
767#[cfg_attr(test, parser_test)]
768fn parse_changed_callback(p: &mut impl Parser) {
774 debug_assert_eq!(p.peek().as_str(), "changed");
775 let mut p = p.start_node(SyntaxKind::PropertyChangedCallback);
776 p.expect(SyntaxKind::Identifier); {
778 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
779 p.expect(SyntaxKind::Identifier);
780 }
781 p.expect(SyntaxKind::FatArrow);
782
783 if p.nth(0).kind() == SyntaxKind::LBrace && p.nth(2).kind() != SyntaxKind::Colon {
784 parse_code_block(&mut *p);
785 p.test(SyntaxKind::Semicolon);
786 } else if parse_expression(&mut *p) {
787 p.expect(SyntaxKind::Semicolon);
788 } else {
789 p.test(SyntaxKind::Semicolon);
790 }
791}
792
793#[cfg_attr(test, parser_test)]
794fn parse_states(p: &mut impl Parser) {
799 debug_assert_eq!(p.peek().as_str(), "states");
800 let mut p = p.start_node(SyntaxKind::States);
801 p.expect(SyntaxKind::Identifier); p.expect(SyntaxKind::LBracket);
803 while parse_state(&mut *p) {}
804 p.expect(SyntaxKind::RBracket);
805}
806
807#[cfg_attr(test, parser_test)]
808fn parse_state(p: &mut impl Parser) -> bool {
815 if p.nth(0).kind() != SyntaxKind::Identifier {
816 return false;
817 }
818 let mut p = p.start_node(SyntaxKind::State);
819 {
820 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
821 p.expect(SyntaxKind::Identifier);
822 }
823 if p.peek().as_str() == "when" {
824 p.consume();
825 parse_expression(&mut *p);
826 }
827 p.expect(SyntaxKind::Colon);
828 if !p.expect(SyntaxKind::LBrace) {
829 return false;
830 }
831
832 loop {
833 match p.nth(0).kind() {
834 SyntaxKind::RBrace => {
835 p.consume();
836 return true;
837 }
838 SyntaxKind::Eof => return false,
839 _ => {
840 if p.nth(1).kind() == SyntaxKind::LBrace
841 && matches!(p.peek().as_str(), "in" | "out" | "in-out" | "in_out")
842 {
843 let mut p = p.start_node(SyntaxKind::Transition);
844 p.consume(); p.expect(SyntaxKind::LBrace);
846 if !parse_transition_inner(&mut *p) {
847 return false;
848 }
849 continue;
850 };
851 let checkpoint = p.checkpoint();
852 if !parse_qualified_name(&mut *p)
853 || !p.expect(SyntaxKind::Colon)
854 || !parse_binding_expression(&mut *p)
855 {
856 p.test(SyntaxKind::RBrace);
857 return false;
858 }
859 let _ = p.start_node_at(checkpoint, SyntaxKind::StatePropertyChange);
860 }
861 }
862 }
863}
864
865#[cfg_attr(test, parser_test)]
866fn parse_transitions(p: &mut impl Parser) {
871 debug_assert_eq!(p.peek().as_str(), "transitions");
872 let mut p = p.start_node(SyntaxKind::Transitions);
873 p.expect(SyntaxKind::Identifier); p.expect(SyntaxKind::LBracket);
875 while p.nth(0).kind() != SyntaxKind::RBracket && parse_transition(&mut *p) {}
876 p.expect(SyntaxKind::RBracket);
877}
878
879#[cfg_attr(test, parser_test)]
880fn parse_transition(p: &mut impl Parser) -> bool {
887 if !matches!(p.peek().as_str(), "in" | "out" | "in-out" | "in_out") {
888 p.error("Expected 'in', 'out', or 'in-out' to declare a transition");
889 return false;
890 }
891 let mut p = p.start_node(SyntaxKind::Transition);
892 p.consume(); {
894 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
895 p.expect(SyntaxKind::Identifier);
896 }
897 p.expect(SyntaxKind::Colon);
898 if !p.expect(SyntaxKind::LBrace) {
899 return false;
900 }
901 parse_transition_inner(&mut *p)
902}
903
904#[cfg_attr(test, parser_test)]
905fn parse_transition_inner(p: &mut impl Parser) -> bool {
910 loop {
911 match p.nth(0).kind() {
912 SyntaxKind::RBrace => {
913 p.consume();
914 return true;
915 }
916 SyntaxKind::Eof => return false,
917 SyntaxKind::Identifier if p.peek().as_str() == "animate" => {
918 parse_property_animation(&mut *p);
919 }
920 _ => {
921 p.consume();
922 p.error("Expected 'animate'");
923 }
924 }
925 }
926}
927
928#[cfg_attr(test, parser_test)]
929fn parse_function<P: Parser>(p: &mut P, checkpoint: Option<P::Checkpoint>) {
939 let checkpoint = checkpoint.unwrap_or_else(|| p.checkpoint());
940 let mut p = p.start_node_at(checkpoint, SyntaxKind::Function);
941 if matches!(p.peek().as_str(), "public" | "protected") {
942 p.consume();
943 if p.peek().as_str() == "pure" {
944 p.consume()
945 }
946 } else if p.peek().as_str() == "pure" {
947 p.consume();
948 if matches!(p.peek().as_str(), "public" | "protected") {
949 p.consume()
950 }
951 }
952 if p.peek().as_str() != "function" {
953 p.error("Unexpected identifier");
954 p.consume();
955 while p.peek().kind == SyntaxKind::Identifier && p.peek().as_str() != "function" {
956 p.consume();
957 }
958 }
959 debug_assert_eq!(p.peek().as_str(), "function");
960 p.expect(SyntaxKind::Identifier); {
962 let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
963 p.expect(SyntaxKind::Identifier);
964 }
965 if p.expect(SyntaxKind::LParent) {
966 while p.peek().kind() != SyntaxKind::RParent {
967 let mut p_arg = p.start_node(SyntaxKind::ArgumentDeclaration);
968 {
969 let mut p = p_arg.start_node(SyntaxKind::DeclaredIdentifier);
970 p.expect(SyntaxKind::Identifier);
971 }
972 p_arg.expect(SyntaxKind::Colon);
973 parse_type(&mut *p_arg);
974 drop(p_arg);
975 if !p.test(SyntaxKind::Comma) {
976 break;
977 }
978 }
979 p.expect(SyntaxKind::RParent);
980 if p.test(SyntaxKind::Arrow) {
981 let mut p = p.start_node(SyntaxKind::ReturnType);
982 parse_type(&mut *p);
983 }
984 }
985
986 if p.peek().kind() == SyntaxKind::LBrace {
987 parse_code_block(&mut *p);
988 } else if !p.test(SyntaxKind::Semicolon) {
989 p.error("Expected function body or semicolon");
990 }
991}