i_slint_compiler/parser/
element.rs

1// Copyright © SixtyFPS GmbH <info@slint.dev>
2// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3
4//! The parser functions for elements and things inside them
5
6use 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)]
13/// ```test,Element
14/// Item { }
15/// Item { property: value; SubElement { } }
16/// Item { if true: Rectangle {} }
17/// ```
18pub 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            // recover
23            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)]
40/// ```test
41/// property1: value; property2: value;
42/// sub := Sub { }
43/// for xx in model: Sub {}
44/// if condition : Sub {}
45/// clicked => {}
46/// callback foobar;
47/// property<int> width;
48/// animate someProp { }
49/// animate * { }
50/// @children
51/// double_binding <=> element.property;
52/// public pure function foo() {}
53/// changed foo => {}
54/// ```
55pub 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                        // Try to recover some errors
118                        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)]
152/// ```test,SubElement
153/// Bar {}
154/// foo := Bar {}
155/// Bar { x : y ; }
156/// ```
157/// Must consume at least one token
158fn 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)]
168/// ```test,RepeatedElement
169/// for xx in mm: Elem { }
170/// for [idx] in mm: Elem { }
171/// for xx [idx] in foo.bar: Elem { }
172/// for _ in (xxx()): blah := Elem { Elem{} }
173/// ```
174/// Must consume at least one token
175fn 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); // "for"
179    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(); // "in"
196    parse_expression(&mut *p);
197    p.expect(SyntaxKind::Colon);
198    parse_sub_element(&mut *p);
199}
200
201#[cfg_attr(test, parser_test)]
202/// ```test,ConditionalElement
203/// if (condition) : Elem { }
204/// if (foo ? bar : xx) : Elem { foo:bar; Elem {}}
205/// if (true) : foo := Elem {}
206/// if true && true : Elem {}
207/// ```
208/// Must consume at least one token
209fn 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); // "if"
213    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)]
222/// ```test,Binding
223/// foo: bar;
224/// foo: {}
225/// ```
226fn 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)]
234/// ```test,BindingExpression
235/// {  }
236/// expression ;
237/// {expression }
238/// {object: 42};
239/// ```
240fn 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)]
255/// ```test,CodeBlock
256/// {  }
257/// { expression }
258/// { expression ; expression }
259/// { expression ; expression ; }
260/// { ;;;; }
261/// ```
262pub fn parse_code_block(p: &mut impl Parser) {
263    let mut p = p.start_node(SyntaxKind::CodeBlock);
264    p.expect(SyntaxKind::LBrace); // Or assert?
265
266    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)]
275/// ```test,CallbackConnection
276/// clicked => {}
277/// clicked() => { foo; }
278/// mouse_move(x, y) => {}
279/// mouse_move(x, y, ) => { bar; goo; }
280/// ```
281fn parse_callback_connection(p: &mut impl Parser) {
282    let mut p = p.start_node(SyntaxKind::CallbackConnection);
283    p.consume(); // the identifier
284    if p.test(SyntaxKind::LParent) {
285        while p.peek().kind() != SyntaxKind::RParent {
286            {
287                let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
288                p.expect(SyntaxKind::Identifier);
289            }
290            if !p.test(SyntaxKind::Comma) {
291                break;
292            }
293        }
294        p.expect(SyntaxKind::RParent);
295    }
296    p.expect(SyntaxKind::FatArrow);
297    parse_code_block(&mut *p);
298}
299
300#[cfg_attr(test, parser_test)]
301/// ```test,TwoWayBinding
302/// foo <=> bar;
303/// foo <=> bar.xxx;
304/// ```
305fn parse_two_way_binding(p: &mut impl Parser) {
306    let mut p = p.start_node(SyntaxKind::TwoWayBinding);
307    p.consume(); // the identifier
308    p.expect(SyntaxKind::DoubleArrow);
309    parse_expression(&mut *p);
310    p.expect(SyntaxKind::Semicolon);
311}
312
313#[cfg_attr(test, parser_test)]
314/// ```test,CallbackDeclaration
315/// callback foobar;
316/// callback my_callback();
317/// callback foo(int, string);
318/// callback foo(foo: int, string, xx: { a: string });
319/// pure callback one_arg({ a: string, b: string});
320/// callback end_coma(a, b, c,);
321/// callback with_return(a, b) -> int;
322/// callback with_return2({a: string}) -> { a: string };
323/// callback foobar <=> elem.foobar;
324/// ```
325/// Must consume at least one token
326fn parse_callback_declaration(p: &mut impl Parser) {
327    let mut p = p.start_node(SyntaxKind::CallbackDeclaration);
328    if p.peek().as_str() == "pure" {
329        p.consume();
330    }
331    debug_assert_eq!(p.peek().as_str(), "callback");
332    p.expect(SyntaxKind::Identifier); // "callback"
333    {
334        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
335        p.expect(SyntaxKind::Identifier);
336    }
337    if p.test(SyntaxKind::LParent) {
338        while p.peek().kind() != SyntaxKind::RParent {
339            {
340                let mut p = p.start_node(SyntaxKind::CallbackDeclarationParameter);
341                if p.peek().kind() == SyntaxKind::Identifier && p.nth(1).kind() == SyntaxKind::Colon
342                {
343                    {
344                        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
345                        p.expect(SyntaxKind::Identifier);
346                    }
347                    p.expect(SyntaxKind::Colon);
348                }
349                parse_type(&mut *p);
350            }
351            if !p.test(SyntaxKind::Comma) {
352                break;
353            }
354        }
355        p.expect(SyntaxKind::RParent);
356        if p.test(SyntaxKind::Arrow) {
357            let mut p = p.start_node(SyntaxKind::ReturnType);
358            parse_type(&mut *p);
359        }
360
361        if p.peek().kind() == SyntaxKind::DoubleArrow {
362            p.error("When declaring a callback alias, one must omit parentheses. e.g. 'callback foo <=> other.bar;'");
363        }
364    } else if p.test(SyntaxKind::Arrow) {
365        // Force callback with return value to also have parentheses, we could remove this
366        // restriction in the future
367        p.error("Callback with return value must be declared with parentheses e.g. 'callback foo() -> int;'");
368        parse_type(&mut *p);
369    }
370
371    if p.peek().kind() == SyntaxKind::DoubleArrow {
372        let mut p = p.start_node(SyntaxKind::TwoWayBinding);
373        p.expect(SyntaxKind::DoubleArrow);
374        parse_expression(&mut *p);
375    }
376
377    p.expect(SyntaxKind::Semicolon);
378}
379
380#[cfg_attr(test, parser_test)]
381/// ```test,PropertyDeclaration
382/// in property <int> xxx;
383/// property<int> foobar;
384/// property<string> text: "Something";
385/// property<string> text <=> two.way;
386/// property alias <=> two.way;
387/// ```
388fn parse_property_declaration(p: &mut impl Parser) {
389    let checkpoint = p.checkpoint();
390    while matches!(p.peek().as_str(), "in" | "out" | "in-out" | "in_out" | "private") {
391        p.consume();
392    }
393    if p.peek().as_str() != "property" {
394        p.error("Expected 'property' keyword");
395        return;
396    }
397    let mut p = p.start_node_at(checkpoint, SyntaxKind::PropertyDeclaration);
398    p.consume(); // property
399
400    if p.test(SyntaxKind::LAngle) {
401        parse_type(&mut *p);
402        p.expect(SyntaxKind::RAngle);
403    } else if p.nth(0).kind() == SyntaxKind::Identifier
404        && p.nth(1).kind() != SyntaxKind::DoubleArrow
405    {
406        p.error("Missing type. The syntax to declare a property is `property <type> name;`. Only two way bindings can omit the type");
407    }
408
409    {
410        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
411        p.expect(SyntaxKind::Identifier);
412    }
413
414    match p.nth(0).kind() {
415        SyntaxKind::Colon => {
416            p.consume();
417            parse_binding_expression(&mut *p);
418        }
419        SyntaxKind::DoubleArrow => {
420            let mut p = p.start_node(SyntaxKind::TwoWayBinding);
421            p.consume();
422            parse_expression(&mut *p);
423            p.expect(SyntaxKind::Semicolon);
424        }
425        _ => {
426            p.expect(SyntaxKind::Semicolon);
427        }
428    }
429}
430
431#[cfg_attr(test, parser_test)]
432/// ```test,PropertyAnimation
433/// animate x { duration: 1000; }
434/// animate x, foo.y {  }
435/// animate * {  }
436/// ```
437fn parse_property_animation(p: &mut impl Parser) {
438    debug_assert_eq!(p.peek().as_str(), "animate");
439    let mut p = p.start_node(SyntaxKind::PropertyAnimation);
440    p.expect(SyntaxKind::Identifier); // animate
441    if p.nth(0).kind() == SyntaxKind::Star {
442        p.consume();
443    } else {
444        parse_qualified_name(&mut *p);
445        while p.nth(0).kind() == SyntaxKind::Comma {
446            p.consume();
447            parse_qualified_name(&mut *p);
448        }
449    };
450    p.expect(SyntaxKind::LBrace);
451
452    loop {
453        match p.nth(0).kind() {
454            SyntaxKind::RBrace => {
455                p.consume();
456                return;
457            }
458            SyntaxKind::Eof => return,
459            SyntaxKind::Identifier => match p.nth(1).kind() {
460                SyntaxKind::Colon => parse_property_binding(&mut *p),
461                _ => {
462                    p.consume();
463                    p.error("Only bindings are allowed in animations");
464                }
465            },
466            _ => {
467                p.consume();
468                p.error("Only bindings are allowed in animations");
469            }
470        }
471    }
472}
473
474#[cfg_attr(test, parser_test)]
475/// ```test,PropertyChangedCallback
476/// changed the-property => { x = y; }
477/// ```
478fn parse_changed_callback(p: &mut impl Parser) {
479    debug_assert_eq!(p.peek().as_str(), "changed");
480    let mut p = p.start_node(SyntaxKind::PropertyChangedCallback);
481    p.expect(SyntaxKind::Identifier); // changed
482    {
483        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
484        p.expect(SyntaxKind::Identifier);
485    }
486    p.expect(SyntaxKind::FatArrow);
487    parse_code_block(&mut *p);
488}
489
490#[cfg_attr(test, parser_test)]
491/// ```test,States
492/// states []
493/// states [ foo when bar : { x:y; } another_state : { x:z; }]
494/// ```
495fn parse_states(p: &mut impl Parser) {
496    debug_assert_eq!(p.peek().as_str(), "states");
497    let mut p = p.start_node(SyntaxKind::States);
498    p.expect(SyntaxKind::Identifier); // "states"
499    p.expect(SyntaxKind::LBracket);
500    while parse_state(&mut *p) {}
501    p.expect(SyntaxKind::RBracket);
502}
503
504#[cfg_attr(test, parser_test)]
505/// ```test,State
506/// foo : { x: 1px + 2px; aaa.y: {1px + 2px} }
507/// foo when bar == 1:  { color: blue; foo.color: red;   }
508/// a when b:  { color: blue; in { animate color { duration: 120s; } }   }
509/// a when b:  { out { animate foo.bar { } } foo.bar: 42;  }
510/// ```
511fn parse_state(p: &mut impl Parser) -> bool {
512    if p.nth(0).kind() != SyntaxKind::Identifier {
513        return false;
514    }
515    let mut p = p.start_node(SyntaxKind::State);
516    {
517        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
518        p.expect(SyntaxKind::Identifier);
519    }
520    if p.peek().as_str() == "when" {
521        p.consume();
522        parse_expression(&mut *p);
523    }
524    p.expect(SyntaxKind::Colon);
525    if !p.expect(SyntaxKind::LBrace) {
526        return false;
527    }
528
529    loop {
530        match p.nth(0).kind() {
531            SyntaxKind::RBrace => {
532                p.consume();
533                return true;
534            }
535            SyntaxKind::Eof => return false,
536            _ => {
537                if p.nth(1).kind() == SyntaxKind::LBrace
538                    && matches!(p.peek().as_str(), "in" | "out" | "in-out" | "in_out")
539                {
540                    let mut p = p.start_node(SyntaxKind::Transition);
541                    p.consume(); // "in", "out" or "in-out"
542                    p.expect(SyntaxKind::LBrace);
543                    if !parse_transition_inner(&mut *p) {
544                        return false;
545                    }
546                    continue;
547                };
548                let checkpoint = p.checkpoint();
549                if !parse_qualified_name(&mut *p)
550                    || !p.expect(SyntaxKind::Colon)
551                    || !parse_binding_expression(&mut *p)
552                {
553                    p.test(SyntaxKind::RBrace);
554                    return false;
555                }
556                let _ = p.start_node_at(checkpoint, SyntaxKind::StatePropertyChange);
557            }
558        }
559    }
560}
561
562#[cfg_attr(test, parser_test)]
563/// ```test,Transitions
564/// transitions []
565/// transitions [in checked: {animate x { duration: 88ms; }} out checked: {animate x { duration: 88ms; }} in-out checked: {animate x { duration: 88ms; }}]
566/// ```
567fn parse_transitions(p: &mut impl Parser) {
568    debug_assert_eq!(p.peek().as_str(), "transitions");
569    let mut p = p.start_node(SyntaxKind::Transitions);
570    p.expect(SyntaxKind::Identifier); // "transitions"
571    p.expect(SyntaxKind::LBracket);
572    while p.nth(0).kind() != SyntaxKind::RBracket && parse_transition(&mut *p) {}
573    p.expect(SyntaxKind::RBracket);
574}
575
576#[cfg_attr(test, parser_test)]
577/// ```test,Transition
578/// in pressed : {}
579/// in pressed: { animate x { duration: 88ms; } }
580/// out pressed: { animate x { duration: 88ms; } }
581/// in-out pressed: { animate x { duration: 88ms; } }
582/// ```
583fn parse_transition(p: &mut impl Parser) -> bool {
584    if !matches!(p.peek().as_str(), "in" | "out" | "in-out" | "in_out") {
585        p.error("Expected 'in', 'out', or 'in-out' to declare a transition");
586        return false;
587    }
588    let mut p = p.start_node(SyntaxKind::Transition);
589    p.consume(); // "in", "out" or "in-out"
590    {
591        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
592        p.expect(SyntaxKind::Identifier);
593    }
594    p.expect(SyntaxKind::Colon);
595    if !p.expect(SyntaxKind::LBrace) {
596        return false;
597    }
598    parse_transition_inner(&mut *p)
599}
600
601#[cfg_attr(test, parser_test)]
602/// ```test
603/// }
604/// animate x { duration: 88ms; }  animate foo.bar { } }
605/// ```
606fn parse_transition_inner(p: &mut impl Parser) -> bool {
607    loop {
608        match p.nth(0).kind() {
609            SyntaxKind::RBrace => {
610                p.consume();
611                return true;
612            }
613            SyntaxKind::Eof => return false,
614            SyntaxKind::Identifier if p.peek().as_str() == "animate" => {
615                parse_property_animation(&mut *p);
616            }
617            _ => {
618                p.consume();
619                p.error("Expected 'animate'");
620            }
621        }
622    }
623}
624
625#[cfg_attr(test, parser_test)]
626/// ```test,Function
627/// function foo() {}
628/// function bar(xx : int) { yy = xx; }
629/// function bar(xx : int,) -> int { return 42; }
630/// public function aa(x: int, b: {a: int}, c: int) {}
631/// protected pure function fff() {}
632/// ```
633fn parse_function(p: &mut impl Parser) {
634    let mut p = p.start_node(SyntaxKind::Function);
635    if matches!(p.peek().as_str(), "public" | "protected") {
636        p.consume();
637        if p.peek().as_str() == "pure" {
638            p.consume()
639        }
640    } else if p.peek().as_str() == "pure" {
641        p.consume();
642        if matches!(p.peek().as_str(), "public" | "protected") {
643            p.consume()
644        }
645    }
646    if p.peek().as_str() != "function" {
647        p.error("Unexpected identifier");
648        p.consume();
649        while p.peek().kind == SyntaxKind::Identifier && p.peek().as_str() != "function" {
650            p.consume();
651        }
652    }
653    debug_assert_eq!(p.peek().as_str(), "function");
654    p.expect(SyntaxKind::Identifier); // "function"
655    {
656        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
657        p.expect(SyntaxKind::Identifier);
658    }
659    if p.expect(SyntaxKind::LParent) {
660        while p.peek().kind() != SyntaxKind::RParent {
661            let mut p_arg = p.start_node(SyntaxKind::ArgumentDeclaration);
662            {
663                let mut p = p_arg.start_node(SyntaxKind::DeclaredIdentifier);
664                p.expect(SyntaxKind::Identifier);
665            }
666            p_arg.expect(SyntaxKind::Colon);
667            parse_type(&mut *p_arg);
668            drop(p_arg);
669            if !p.test(SyntaxKind::Comma) {
670                break;
671            }
672        }
673        p.expect(SyntaxKind::RParent);
674        if p.test(SyntaxKind::Arrow) {
675            let mut p = p.start_node(SyntaxKind::ReturnType);
676            parse_type(&mut *p);
677        }
678    }
679    parse_code_block(&mut *p);
680}