cas_parser/parser/ast/
stmt.rs

1use crate::parser::{
2    ast::expr::Expr,
3    error::Error,
4    fmt::Latex,
5    token::Semicolon,
6    Parse,
7    Parser,
8};
9use std::{fmt, ops::Range};
10
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Serialize};
13
14/// Represents a statement in CalcScript.
15#[derive(Debug, Clone, PartialEq)]
16#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17pub struct Stmt {
18    /// The expression of a statement.
19    pub expr: Expr,
20
21    /// The span of the semicolon that terminates the statement, if any.
22    ///
23    /// When this is [`None`], the statement is an expression, and will return the value of the
24    /// expression. Otherwise, the expression is evaluated for side effects, and the statement
25    /// returns the unit type `()`.
26    pub semicolon: Option<Range<usize>>,
27
28    /// The region of the source code that this statement was parsed from.
29    pub span: Range<usize>,
30}
31
32impl Stmt {
33    /// Returns the span of the statement.
34    pub fn span(&self) -> Range<usize> {
35        self.span.clone()
36    }
37}
38
39impl<'source> Parse<'source> for Stmt {
40    fn std_parse(
41        input: &mut Parser<'source>,
42        recoverable_errors: &mut Vec<Error>
43    ) -> Result<Self, Vec<Error>> {
44        let expr = input.try_parse::<Expr>().forward_errors(recoverable_errors)?;
45        let semicolon = if let Ok(semi) = input.try_parse::<Semicolon>().forward_errors(recoverable_errors) {
46            Some(semi.span.clone())
47        } else {
48            None
49        };
50        let stmt_span = if let Some(semicolon) = &semicolon {
51            expr.span().start..semicolon.end
52        } else {
53            expr.span()
54        };
55
56        Ok(Stmt {
57            expr,
58            semicolon,
59            span: stmt_span,
60        })
61    }
62}
63
64impl std::fmt::Display for Stmt {
65    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
66        write!(f, "{}", self.expr)?;
67        if self.semicolon.is_some() {
68            write!(f, ";")?;
69        }
70        Ok(())
71    }
72}
73
74impl Latex for Stmt {
75    fn fmt_latex(&self, f: &mut fmt::Formatter) -> fmt::Result {
76        self.expr.fmt_latex(f)?;
77        if self.semicolon.is_some() {
78            write!(f, ";")?;
79        }
80        Ok(())
81    }
82}