Skip to main content

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}