rl_lang/parser/statements/if_statement.rs
1//! Conditional statement parser (`if` / `else if` / `else`).
2//!
3//! Parses the full if-chain into a tree of nested [`StatementKind::Conditional`]
4//! nodes. Each `else if` branch is represented by recursion, so the AST mirrors
5//! the source nesting naturally:
6//!
7//! ```text
8//! if (a) { … } else if (b) { … } else { … }
9//! ```
10//! becomes:
11//! ```text
12//! Conditional {
13//! if_branch: ConditionalBranch { condition: Some(a), body: […] }
14//! else_branch: Some(Conditional {
15//! if_branch: ConditionalBranch { condition: Some(b), body: […] }
16//! else_branch: Some(ConditionalBranch { condition: None, body: […] })
17//! })
18//! }
19//! ```
20
21use crate::{
22 ast::statements::{Statement, StatementKind},
23 lexer::tokentypes::TokenType,
24 parser::parser_logic::Parser,
25 utils::{errors::Error, span::Span},
26};
27
28impl Parser {
29 /// Parses an `if` statement, including any `else if` / `else` tail.
30 ///
31 /// Called after `if` has been consumed. Reads:
32 ///
33 /// 1. The condition expression.
34 /// 2. The `{`-delimited if-body via [`parse_block`].
35 /// 3. An optional `else` tail - either another `if` (recursed) or a plain
36 /// `else { … }` block (condition is `None`).
37 ///
38 /// Blank lines between the closing `}` and `else` are skipped.
39 ///
40 /// Produces [`StatementKind::Conditional`] with one or two
41 /// [`StatementKind::ConditionalBranch`] children.
42 ///
43 /// [`parse_block`]: Parser::parse_block
44 pub fn parse_if(&mut self, start: Span) -> Result<Statement, Error> {
45 while self.match_type(&[TokenType::Newline]) {}
46 let if_condition = self.parse_expression()?;
47 while self.match_type(&[TokenType::Newline]) {}
48 let if_body = self.parse_block()?;
49 let if_branch_span = start.join(self.previous_span());
50 let if_branch = Statement::new(
51 StatementKind::ConditionalBranch {
52 condition: Some(if_condition),
53 body: if_body,
54 needs_scope: true,
55 },
56 if_branch_span,
57 );
58
59 // skip any blank lines between `}` and `else`
60 while self.match_type(&[TokenType::Newline]) {}
61
62 let else_branch = if self.peek() == TokenType::Else {
63 let branch_start = self.peek_span();
64 self.advance();
65 if self.peek() == TokenType::If {
66 // `else if` - recurse to produce a nested Conditional
67 let elif_start = self.peek_span();
68 self.advance();
69 Some(Box::new(self.parse_if(elif_start)?))
70 } else {
71 // plain `else { … }` - condition is None
72 let else_body = self.parse_block()?;
73 let span = branch_start.join(self.previous_span());
74 Some(Box::new(Statement::new(
75 StatementKind::ConditionalBranch {
76 condition: None,
77 body: else_body,
78 needs_scope: true,
79 },
80 span,
81 )))
82 }
83 } else {
84 None
85 };
86
87 let span = start.join(self.previous_span());
88 Ok(Statement::new(
89 StatementKind::Conditional {
90 if_branch: Box::new(if_branch),
91 else_branch,
92 },
93 span,
94 ))
95 }
96}