cas_parser/parser/ast/
index.rs

1use cas_error::Error;
2use crate::parser::{
3    ast::{expr::{Expr, Primary}, helper::Square},
4    fmt::Latex,
5    Parser,
6};
7use std::{fmt, ops::Range};
8
9#[cfg(feature = "serde")]
10use serde::{Deserialize, Serialize};
11
12/// List indexing, such as `list[0]`.
13///
14/// [`Parse`]: crate::parser::Parse
15#[derive(Debug, Clone, PartialEq, Eq)]
16#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17pub struct Index {
18    /// The expression being indexed.
19    pub target: Box<Expr>,
20
21    /// The amount to index by.
22    pub index: Box<Expr>,
23
24    /// The region of the source code that this function call was parsed from.
25    pub span: Range<usize>,
26
27    /// The span of the brackets that surround the index expression.
28    pub bracket_span: Range<usize>,
29}
30
31impl Index {
32    /// Returns the span of the index expression.
33    pub fn span(&self) -> Range<usize> {
34        self.span.clone()
35    }
36
37    /// Returns a set of two spans, where the first is the span of the expression being indexed
38    /// (with the opening bracket) and the second is the span of the closing bracket.
39    pub fn outer_span(&self) -> [Range<usize>; 2] {
40        [
41            self.target.span().start..self.bracket_span.start + 1,
42            self.bracket_span.end - 1..self.bracket_span.end,
43        ]
44    }
45
46    /// Attempts to parse an [`Index`], where the initial target has already been parsed.
47    ///
48    /// Besides the returned [`Primary`], the return value also includes a boolean that indicates
49    /// if the expression was changed due to successfully parsing a [`Index`]. This function can
50    /// return even if no [`Index`], which occurs when we determine that we shouldn't have taken the
51    /// [`Index`] path. The boolean is used to let the caller know that this is was the case.
52    ///
53    /// This is similar to what we had to do with [`Binary`].
54    ///
55    /// [`Binary`]: crate::parser::ast::binary::Binary
56    pub fn parse_or_lower(
57        input: &mut Parser,
58        recoverable_errors: &mut Vec<Error>,
59        mut target: Primary,
60    ) -> (Primary, bool) {
61        let mut changed = false;
62
63        // iteratively search for nested index expressions
64        while let Ok(surrounded) = input.try_parse::<Square<_>>().forward_errors(recoverable_errors) {
65            let span = target.span().start..surrounded.close.span.end;
66            target = Primary::Index(Self {
67                target: Box::new(target.into()),
68                index: Box::new(surrounded.value),
69                span,
70                bracket_span: surrounded.open.span.start..surrounded.close.span.end,
71            });
72            changed = true;
73        }
74
75        (target, changed)
76    }
77}
78
79impl std::fmt::Display for Index {
80    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
81        write!(f, "{}[{}]", self.target, self.index)
82    }
83}
84
85impl Latex for Index {
86    fn fmt_latex(&self, f: &mut fmt::Formatter) -> fmt::Result {
87        write!(f, "{}_{{{}}}", self.target, self.index)
88    }
89}