cas_parser/parser/ast/
return_expr.rs

1use cas_error::Error;
2use crate::parser::{
3    ast::expr::Expr,
4    error::ReturnOutsideFunction,
5    fmt::Latex,
6    keyword::Return as ReturnToken,
7    Parse,
8    Parser,
9};
10use std::{fmt, ops::Range};
11
12#[cfg(feature = "serde")]
13use serde::{Deserialize, Serialize};
14
15/// A `return` expression, used to return a value from a function.
16#[derive(Debug, Clone, PartialEq, Eq)]
17#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
18pub struct Return {
19    /// The value to return from the function.
20    pub value: Option<Box<Expr>>,
21
22    /// The region of the source code that this expression was parsed from.
23    pub span: Range<usize>,
24
25    /// The span of the `return` keyword.
26    pub return_span: Range<usize>,
27}
28
29impl Return {
30    /// Returns the span of the `return` expression.
31    pub fn span(&self) -> Range<usize> {
32        self.span.clone()
33    }
34}
35
36impl<'source> Parse<'source> for Return {
37    fn std_parse(
38        input: &mut Parser<'source>,
39        recoverable_errors: &mut Vec<Error>
40    ) -> Result<Self, Vec<Error>> {
41        let return_token = input.try_parse::<ReturnToken>().forward_errors(recoverable_errors)?;
42        let value = input.try_parse_with_state::<_, Expr>(|state| {
43            state.expr_end_at_eol = true;
44        }).forward_errors(recoverable_errors).ok();
45        let span = if let Some(value) = &value {
46            return_token.span.start..value.span().end
47        } else {
48            return_token.span.clone()
49        };
50
51        // `return` expressions can only be used inside functions
52        if !input.state.allow_return {
53            recoverable_errors.push(Error::new(
54                vec![return_token.span.clone()],
55                ReturnOutsideFunction,
56            ));
57        }
58
59        Ok(Self {
60            value: value.map(Box::new),
61            span,
62            return_span: return_token.span,
63        })
64    }
65}
66
67impl std::fmt::Display for Return {
68    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
69        write!(f, "return")?;
70        if let Some(value) = &self.value {
71            write!(f, " {}", value)?;
72        }
73        Ok(())
74    }
75}
76
77impl Latex for Return {
78    fn fmt_latex(&self, f: &mut fmt::Formatter) -> fmt::Result {
79        write!(f, "\\text{{return }}")?;
80        if let Some(value) = &self.value {
81            value.fmt_latex(f)?;
82        }
83        Ok(())
84    }
85}