| 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 | use super::element::parse_code_block; |
| 5 | use super::expressions::parse_expression; |
| 6 | use 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 | /// ``` |
| 18 | pub 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 | /// ``` |
| 77 | fn parse_if_statement(p: &mut impl Parser) { |
| 78 | let mut p: Node<'_, impl Parser> = p.start_node(kind:SyntaxKind::ConditionalExpression); |
| 79 | debug_assert_eq!(p.peek().as_str(), "if" ); |
| 80 | p.expect(kind:SyntaxKind::Identifier); |
| 81 | parse_expression(&mut *p); |
| 82 | { |
| 83 | let mut p: Node<'_, impl Parser> = p.start_node(kind:SyntaxKind::Expression); |
| 84 | parse_code_block(&mut *p); |
| 85 | } |
| 86 | if p.peek().as_str() == "else" { |
| 87 | p.expect(kind:SyntaxKind::Identifier); |
| 88 | let mut p: Node<'_, impl Parser> = p.start_node(kind: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: Node<'_, impl Parser> = p.start_node(kind:SyntaxKind::Expression); |
| 98 | let _ = p.start_node(kind:SyntaxKind::CodeBlock); |
| 99 | } |
| 100 | } |
| 101 | |