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}