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 => bar ;
278/// clicked => { foo; } ;
279/// clicked() => { foo; }
280/// mouse_move(x, y) => {}
281/// mouse_move(x, y, ) => { bar; goo; }
282/// ```
283fn parse_callback_connection(p: &mut impl Parser) {
284    let mut p = p.start_node(SyntaxKind::CallbackConnection);
285    p.consume(); // the identifier
286    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)]
310/// ```test,TwoWayBinding
311/// foo <=> bar;
312/// foo <=> bar.xxx;
313/// ```
314fn parse_two_way_binding(p: &mut impl Parser) {
315    let mut p = p.start_node(SyntaxKind::TwoWayBinding);
316    p.consume(); // the identifier
317    p.expect(SyntaxKind::DoubleArrow);
318    parse_expression(&mut *p);
319    p.expect(SyntaxKind::Semicolon);
320}
321
322#[cfg_attr(test, parser_test)]
323/// ```test,CallbackDeclaration
324/// callback foobar;
325/// callback my_callback();
326/// callback foo(int, string);
327/// callback foo(foo: int, string, xx: { a: string });
328/// pure callback one_arg({ a: string, b: string});
329/// callback end_coma(a, b, c,);
330/// callback with_return(a, b) -> int;
331/// callback with_return2({a: string}) -> { a: string };
332/// callback foobar <=> elem.foobar;
333/// ```
334/// Must consume at least one token
335fn 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); // "callback"
342    {
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        // Force callback with return value to also have parentheses, we could remove this
375        // restriction in the future
376        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)]
390/// ```test,PropertyDeclaration
391/// in property <int> xxx;
392/// property<int> foobar;
393/// property<string> text: "Something";
394/// property<string> text <=> two.way;
395/// property alias <=> two.way;
396/// ```
397fn 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(); // property
408
409    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)]
441/// ```test,PropertyAnimation
442/// animate x { duration: 1000; }
443/// animate x, foo.y {  }
444/// animate * {  }
445/// ```
446fn 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); // animate
450    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)]
484/// ```test,PropertyChangedCallback
485/// changed the-property => { x = y; }
486/// changed foo => debug(13);
487/// changed xyz => { foo() };
488/// ```
489fn 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); // changed
493    {
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)]
510/// ```test,States
511/// states []
512/// states [ foo when bar : { x:y; } another_state : { x:z; }]
513/// ```
514fn 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); // "states"
518    p.expect(SyntaxKind::LBracket);
519    while parse_state(&mut *p) {}
520    p.expect(SyntaxKind::RBracket);
521}
522
523#[cfg_attr(test, parser_test)]
524/// ```test,State
525/// foo : { x: 1px + 2px; aaa.y: {1px + 2px} }
526/// foo when bar == 1:  { color: blue; foo.color: red;   }
527/// a when b:  { color: blue; in { animate color { duration: 120s; } }   }
528/// a when b:  { out { animate foo.bar { } } foo.bar: 42;  }
529/// ```
530fn 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(); // "in", "out" or "in-out"
561                    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)]
582/// ```test,Transitions
583/// transitions []
584/// transitions [in checked: {animate x { duration: 88ms; }} out checked: {animate x { duration: 88ms; }} in-out checked: {animate x { duration: 88ms; }}]
585/// ```
586fn 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); // "transitions"
590    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)]
596/// ```test,Transition
597/// in pressed : {}
598/// in pressed: { animate x { duration: 88ms; } }
599/// out pressed: { animate x { duration: 88ms; } }
600/// in-out pressed: { animate x { duration: 88ms; } }
601/// ```
602fn 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(); // "in", "out" or "in-out"
609    {
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)]
621/// ```test
622/// }
623/// animate x { duration: 88ms; }  animate foo.bar { } }
624/// ```
625fn 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)]
645/// ```test,Function
646/// function foo() {}
647/// function bar(xx : int) { yy = xx; }
648/// function bar(xx : int,) -> int { return 42; }
649/// public function aa(x: int, b: {a: int}, c: int) {}
650/// protected pure function fff() {}
651/// ```
652fn 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); // "function"
674    {
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}