cas_parser/parser/ast/
if_expr.rs1use 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#[derive(Debug, Clone, PartialEq)]
17#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
18pub struct If {
19 pub condition: Box<Expr>,
21
22 pub then_expr: Box<Expr>,
24
25 pub else_expr: Option<Box<Expr>>,
27
28 pub span: Range<usize>,
30
31 pub if_span: Range<usize>,
33
34 pub then_span: Range<usize>,
36
37 pub else_span: Option<Range<usize>>,
39}
40
41impl If {
42 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}