cas_parser/parser/ast/
if_expr.rs1use cas_error::Error;
2use crate::parser::{
3 ast::expr::{Atom, Expr},
4 error::MissingIfBranch,
5 fmt::Latex,
6 garbage::Garbage,
7 keyword::{Else, If as IfToken},
8 Parse,
9 Parser,
10};
11use std::{fmt, ops::Range};
12
13#[cfg(feature = "serde")]
14use serde::{Deserialize, Serialize};
15
16#[derive(Debug, Clone, PartialEq, Eq)]
18#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
19pub struct If {
20 pub condition: Box<Expr>,
22
23 pub then_expr: Box<Expr>,
25
26 pub else_expr: Option<Box<Expr>>,
28
29 pub span: Range<usize>,
31
32 pub if_span: Range<usize>,
34
35 pub else_span: Option<Range<usize>>,
37}
38
39impl If {
40 pub fn span(&self) -> Range<usize> {
42 self.span.clone()
43 }
44}
45
46impl<'source> Parse<'source> for If {
47 fn std_parse(
48 input: &mut Parser<'source>,
49 recoverable_errors: &mut Vec<Error>
50 ) -> Result<Self, Vec<Error>> {
51 let if_token = input.try_parse::<IfToken>().forward_errors(recoverable_errors)?;
52 let condition = input.try_parse().forward_errors(recoverable_errors)?;
53 let then_expr = input.try_parse_with_state::<_, Atom>(|input| {
54 input.allow_then = true;
55 })
56 .map(Expr::from)
57 .forward_errors(recoverable_errors)?;
58 let (else_token, else_expr) = 'else_branch: {
59 let Ok(else_token) = input.try_parse::<Else>().forward_errors(recoverable_errors) else {
60 break 'else_branch (None, None);
61 };
62 input.try_parse::<Expr>()
63 .forward_errors(recoverable_errors)
64 .map(|expr| (Some(else_token), Some(expr)))
65 .unwrap_or_else(|_| {
66 recoverable_errors.push(Error::new(
67 vec![if_token.span.clone(), input.span()],
68 MissingIfBranch {
69 keyword: "else",
70 },
71 ));
72 Garbage::garbage()
73 })
74 };
75 let span = if let Some(else_expr) = &else_expr {
76 if_token.span.start..else_expr.span().end
77 } else {
78 if_token.span.start..then_expr.span().end
79 };
80
81 Ok(Self {
82 condition: Box::new(condition),
83 then_expr: Box::new(then_expr),
84 else_expr: else_expr.map(Box::new),
85 span,
86 if_span: if_token.span,
87 else_span: else_token.map(|token| token.span),
88 })
89 }
90}
91
92impl std::fmt::Display for If {
93 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
94 write!(f, "if ")?;
95 self.condition.fmt(f)?;
96 self.then_expr.fmt(f)?;
97 if let Some(else_expr) = &self.else_expr {
98 write!(f, " else ")?;
99 else_expr.fmt(f)?;
100 }
101 Ok(())
102 }
103}
104
105impl Latex for If {
106 fn fmt_latex(&self, f: &mut fmt::Formatter) -> fmt::Result {
107 write!(f, "\\text{{if }}")?;
108 self.condition.fmt_latex(f)?;
109 self.then_expr.fmt_latex(f)?;
110 if let Some(else_expr) = &self.else_expr {
111 write!(f, "\\text{{ else }}")?;
112 else_expr.fmt_latex(f)?;
113 }
114 Ok(())
115 }
116}