i_slint_compiler/parser/
statements.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
4use crate::parser::r#type::parse_type;
5
6use super::element::parse_code_block;
7use super::expressions::parse_expression;
8use super::prelude::*;
9
10#[cfg_attr(test, parser_test)]
11/// ```test
12/// expression
13/// expression += expression
14/// expression.expression *= 45.2
15/// expression = "hello"
16/// if (true) { foo = bar; } else { bar = foo;  }
17/// return;
18/// if (true) { return 42; }
19/// let foo = 1;
20/// let bar = foo;
21/// let str: string = "hello world";
22/// ```
23pub fn parse_statement(p: &mut impl Parser) -> bool {
24    if p.nth(0).kind() == SyntaxKind::RBrace {
25        return false;
26    }
27    if p.test(SyntaxKind::Semicolon) {
28        return true;
29    }
30    let checkpoint = p.checkpoint();
31
32    if p.peek().as_str() == "if"
33        && !matches!(
34            p.nth(1).kind(),
35            SyntaxKind::Dot
36                | SyntaxKind::Comma
37                | SyntaxKind::Semicolon
38                | SyntaxKind::RBrace
39                | SyntaxKind::RBracket
40                | SyntaxKind::RParent
41        )
42    {
43        let mut p = p.start_node(SyntaxKind::Expression);
44        parse_if_statement(&mut *p);
45        return true;
46    }
47
48    if p.peek().as_str() == "return" {
49        let mut p = p.start_node_at(checkpoint, SyntaxKind::ReturnStatement);
50        p.expect(SyntaxKind::Identifier); // "return"
51        if !p.test(SyntaxKind::Semicolon) {
52            parse_expression(&mut *p);
53            p.expect(SyntaxKind::Semicolon);
54        }
55        return true;
56    }
57
58    if p.peek().as_str() == "let" && p.nth(1).kind() == SyntaxKind::Identifier {
59        parse_let_statement(p);
60        return true;
61    }
62
63    parse_expression(p);
64    if matches!(
65        p.nth(0).kind(),
66        SyntaxKind::MinusEqual
67            | SyntaxKind::PlusEqual
68            | SyntaxKind::StarEqual
69            | SyntaxKind::DivEqual
70            | SyntaxKind::Equal
71    ) {
72        let mut p = p.start_node_at(checkpoint.clone(), SyntaxKind::Expression);
73        let mut p = p.start_node_at(checkpoint, SyntaxKind::SelfAssignment);
74        p.consume();
75        parse_expression(&mut *p);
76    }
77    p.test(SyntaxKind::Semicolon)
78}
79
80#[cfg_attr(test, parser_test)]
81/// ```test,LetStatement
82/// let foo = 1;
83/// let bar = foo;
84/// let str: string = "hello world";
85/// ```
86fn parse_let_statement(p: &mut impl Parser) {
87    let mut p = p.start_node(SyntaxKind::LetStatement);
88    debug_assert_eq!(p.peek().as_str(), "let");
89    p.expect(SyntaxKind::Identifier); // "let"
90    {
91        let mut p = p.start_node(SyntaxKind::DeclaredIdentifier);
92        p.expect(SyntaxKind::Identifier);
93    }
94
95    if p.test(SyntaxKind::Colon) {
96        parse_type(&mut *p);
97    }
98
99    p.expect(SyntaxKind::Equal);
100    parse_expression(&mut *p);
101    p.expect(SyntaxKind::Semicolon);
102}
103
104#[cfg_attr(test, parser_test)]
105/// ```test,ConditionalExpression
106/// if (true) { foo = bar; } else { bar = foo;  }
107/// if (true) { foo += bar; }
108/// if (true) { } else { ; }
109/// if (true) { } else if (false) { } else if (xxx) { }
110/// ```
111fn parse_if_statement(p: &mut impl Parser) {
112    let mut p = p.start_node(SyntaxKind::ConditionalExpression);
113    debug_assert_eq!(p.peek().as_str(), "if");
114    p.expect(SyntaxKind::Identifier);
115    parse_expression(&mut *p);
116    {
117        let mut p = p.start_node(SyntaxKind::Expression);
118        parse_code_block(&mut *p);
119    }
120    if p.peek().as_str() == "else" {
121        p.expect(SyntaxKind::Identifier);
122        let mut p = p.start_node(SyntaxKind::Expression);
123        if p.peek().as_str() == "if" {
124            parse_if_statement(&mut *p)
125        } else {
126            parse_code_block(&mut *p);
127        }
128    } else {
129        // We need an expression so fake an empty block.
130        // FIXME: this shouldn't be needed
131        let mut p = p.start_node(SyntaxKind::Expression);
132        let _ = p.start_node(SyntaxKind::CodeBlock);
133    }
134}