cas_parser/parser/ast/
for_expr.rs

1use cas_error::Error;
2use crate::parser::{
3    ast::{
4        expr::Expr,
5        literal::LitSym,
6        range::Range as RangeExpr,
7    },
8    fmt::Latex,
9    keyword::{In as InToken, For as ForToken},
10    Parse,
11    Parser,
12};
13use std::{fmt, ops::Range};
14
15#[cfg(feature = "serde")]
16use serde::{Deserialize, Serialize};
17
18/// A `for` loop expression, such as `for i in 0..10 then print(i)`. The loop body is executed for
19/// each value in the specified range, with the variable taking on the current value.
20#[derive(Debug, Clone, PartialEq, Eq)]
21#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
22pub struct For {
23    /// The variable name representing each value in the range.
24    pub variable: LitSym,
25
26    /// The range of values that the variable will take on.
27    pub range: RangeExpr,
28
29    /// The body of the summation.
30    pub body: Box<Expr>,
31
32    /// The region of the source code that this `for` expression was parsed from.
33    pub span: Range<usize>,
34}
35
36impl For {
37    /// Returns the span of the `for` expression.
38    pub fn span(&self) -> Range<usize> {
39        self.span.clone()
40    }
41}
42
43impl<'source> Parse<'source> for For {
44    fn std_parse(
45        input: &mut Parser<'source>,
46        recoverable_errors: &mut Vec<Error>
47    ) -> Result<Self, Vec<Error>> {
48        let for_token = input.try_parse::<ForToken>().forward_errors(recoverable_errors)?;
49        let variable = input.try_parse::<LitSym>().forward_errors(recoverable_errors)?;
50        input.try_parse::<InToken>().forward_errors(recoverable_errors)?;
51        let range = input.try_parse::<RangeExpr>().forward_errors(recoverable_errors)?;
52        let body = input.try_parse_with_state::<_, Expr>(|state| {
53            state.allow_then = true;
54            state.allow_loop_control = true;
55        }).forward_errors(recoverable_errors)?;
56        let span = for_token.span.start..body.span().end;
57
58        Ok(Self {
59            variable,
60            range,
61            body: Box::new(body),
62            span,
63        })
64    }
65}
66
67impl std::fmt::Display for For {
68    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69        write!(f, "for {} in {} {}", self.variable, self.range, self.body)
70    }
71}
72
73impl Latex for For {
74    fn fmt_latex(&self, f: &mut fmt::Formatter) -> fmt::Result {
75        write!(
76            f,
77            "\\forall {} \\in {} \\text{{ do }} {}",
78            self.variable,
79            self.range,
80            self.body
81        )
82    }
83}