use cas_error::Error;
use crate::parser::{
ast::{
expr::Expr,
literal::LitSym,
range::Range as RangeExpr,
},
fmt::Latex,
keyword::{In as InToken, Sum as SumToken},
Parse,
Parser,
};
use std::{fmt, ops::Range};
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Sum {
pub variable: LitSym,
pub range: RangeExpr,
pub body: Box<Expr>,
pub span: Range<usize>,
}
impl Sum {
pub fn span(&self) -> Range<usize> {
self.span.clone()
}
}
impl<'source> Parse<'source> for Sum {
fn std_parse(
input: &mut Parser<'source>,
recoverable_errors: &mut Vec<Error>
) -> Result<Self, Vec<Error>> {
let sum_token = input.try_parse::<SumToken>().forward_errors(recoverable_errors)?;
let variable = input.try_parse::<LitSym>().forward_errors(recoverable_errors)?;
input.try_parse::<InToken>().forward_errors(recoverable_errors)?;
let range = input.try_parse::<RangeExpr>().forward_errors(recoverable_errors)?;
let body = input.try_parse_with_state::<_, Expr>(|state| {
state.allow_of = true;
}).forward_errors(recoverable_errors)?;
let span = sum_token.span.start..body.span().end;
Ok(Self {
variable,
range,
body: Box::new(body),
span,
})
}
}
impl std::fmt::Display for Sum {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "sum {} in {} {}", self.variable, self.range, self.body)
}
}
impl Latex for Sum {
fn fmt_latex(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"\\sum_{{{}={}}}^{{{}}} {}",
self.variable,
self.range.start,
self.range.end,
self.body,
)
}
}