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