cas_parser/parser/ast/
if_expr.rs

1use crate::parser::{
2    ast::expr::Expr,
3    error::{kind, Error},
4    fmt::Latex,
5    garbage::Garbage,
6    keyword::{Else, If as IfToken, Then},
7    Parse,
8    Parser,
9};
10use std::{fmt, ops::Range};
11
12#[cfg(feature = "serde")]
13use serde::{Deserialize, Serialize};
14
15/// An `if` expression, such as `if true 1 else 2`.
16#[derive(Debug, Clone, PartialEq)]
17#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
18pub struct If {
19    /// The condition of the `if` expression.
20    pub condition: Box<Expr>,
21
22    /// The expression to evaluate if the condition is true.
23    pub then_expr: Box<Expr>,
24
25    /// The expression to evaluate if the condition is false.
26    pub else_expr: Option<Box<Expr>>,
27
28    /// The region of the source code that this literal was parsed from.
29    pub span: Range<usize>,
30
31    /// The span of the `if` keyword.
32    pub if_span: Range<usize>,
33
34    /// The span of the `then` keyword.
35    pub then_span: Range<usize>,
36
37    /// The span of the `else` keyword.
38    pub else_span: Option<Range<usize>>,
39}
40
41impl If {
42    /// Returns the span of the `if` expression.
43    pub fn span(&self) -> Range<usize> {
44        self.span.clone()
45    }
46}
47
48impl<'source> Parse<'source> for If {
49    fn std_parse(
50        input: &mut Parser<'source>,
51        recoverable_errors: &mut Vec<Error>
52    ) -> Result<Self, Vec<Error>> {
53        let if_token = input.try_parse::<IfToken>().forward_errors(recoverable_errors)?;
54        let condition = input.try_parse().forward_errors(recoverable_errors)?;
55        let (then_token, then_expr) = 'then: {
56            let then_token = match input.try_parse::<Then>().forward_errors(recoverable_errors) {
57                Ok(token) => token,
58                Err(_) => {
59                    recoverable_errors.push(Error::new(
60                        vec![if_token.span.clone(), input.span()],
61                        kind::MissingIfKeyword {
62                            keyword: "then",
63                        },
64                    ));
65                    break 'then Garbage::garbage();
66                },
67            };
68            input.try_parse::<Expr>()
69                .forward_errors(recoverable_errors)
70                .map(|expr| (then_token, expr))
71                .unwrap_or_else(|_| {
72                    recoverable_errors.push(Error::new(
73                        vec![if_token.span.clone(), input.span()],
74                        kind::MissingIfBranch {
75                            keyword: "then",
76                        },
77                    ));
78                    Garbage::garbage()
79                })
80        };
81        let (else_token, else_expr) = 'else_branch: {
82            let Ok(else_token) = input.try_parse::<Else>().forward_errors(recoverable_errors) else {
83                break 'else_branch (None, None);
84            };
85            input.try_parse::<Expr>()
86                .forward_errors(recoverable_errors)
87                .map(|expr| (Some(else_token), Some(expr)))
88                .unwrap_or_else(|_| {
89                    recoverable_errors.push(Error::new(
90                        vec![if_token.span.clone(), input.span()],
91                        kind::MissingIfBranch {
92                            keyword: "else",
93                        },
94                    ));
95                    Garbage::garbage()
96                })
97        };
98        let span = if let Some(else_expr) = &else_expr {
99            if_token.span.start..else_expr.span().end
100        } else {
101            if_token.span.start..then_expr.span().end
102        };
103
104        Ok(Self {
105            condition: Box::new(condition),
106            then_expr: Box::new(then_expr),
107            else_expr: else_expr.map(Box::new),
108            span,
109            if_span: if_token.span,
110            then_span: then_token.span,
111            else_span: else_token.map(|token| token.span),
112        })
113    }
114}
115
116impl std::fmt::Display for If {
117    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
118        write!(f, "if ")?;
119        self.condition.fmt(f)?;
120        write!(f, " then ")?;
121        self.then_expr.fmt(f)?;
122        if let Some(else_expr) = &self.else_expr {
123            write!(f, " else ")?;
124            else_expr.fmt(f)?;
125        }
126        Ok(())
127    }
128}
129
130impl Latex for If {
131    fn fmt_latex(&self, f: &mut fmt::Formatter) -> fmt::Result {
132        write!(f, "\\text{{if }}")?;
133        self.condition.fmt_latex(f)?;
134        write!(f, "\\text{{ then }}")?;
135        self.then_expr.fmt_latex(f)?;
136        if let Some(else_expr) = &self.else_expr {
137            write!(f, "\\text{{ else }}")?;
138            else_expr.fmt_latex(f)?;
139        }
140        Ok(())
141    }
142}