use std::fmt; use bitcode::{Decode, Encode}; use serde::{Deserialize, Serialize}; use crate::language::Language; use super::{lexer::LexerError, types::ParsedReference}; #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub enum OpCompare { LessThan, GreaterThan, Equal, LessOrEqualThan, GreaterOrEqualThan, NonEqual, } impl fmt::Display for OpCompare { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { OpCompare::LessThan => write!(fmt, "<"), OpCompare::GreaterThan => write!(fmt, ">"), OpCompare::Equal => write!(fmt, "="), OpCompare::LessOrEqualThan => write!(fmt, "<="), OpCompare::GreaterOrEqualThan => write!(fmt, ">="), OpCompare::NonEqual => write!(fmt, "<>"), } } } #[derive(Debug, PartialEq, Eq, Clone)] pub enum OpUnary { Minus, Percentage, } impl fmt::Display for OpUnary { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { OpUnary::Minus => write!(fmt, "-"), OpUnary::Percentage => write!(fmt, "%"), } } } #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub enum OpSum { Add, Minus, } impl fmt::Display for OpSum { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { OpSum::Add => write!(fmt, "+"), OpSum::Minus => write!(fmt, "-"), } } } #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] pub enum OpProduct { Times, Divide, } impl fmt::Display for OpProduct { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { OpProduct::Times => write!(fmt, "*"), OpProduct::Divide => write!(fmt, "/"), } } } /// List of `errors` /// Note that "#ERROR!" and "#N/IMPL!" are not part of the xlsx standard /// * "#ERROR!" means there was an error processing the formula (for instance "=A1+") /// * "#N/IMPL!" means the formula or feature in Excel but has not been implemented in IronCalc /// Note that they are serialized/deserialized by index #[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)] pub enum Error { REF, NAME, VALUE, DIV, NA, NUM, ERROR, NIMPL, SPILL, CALC, CIRC, NULL, } impl fmt::Display for Error { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { match self { Error::NULL => write!(fmt, "#NULL!"), Error::REF => write!(fmt, "#REF!"), Error::NAME => write!(fmt, "#NAME?"), Error::VALUE => write!(fmt, "#VALUE!"), Error::DIV => write!(fmt, "#DIV/0!"), Error::NA => write!(fmt, "#N/A"), Error::NUM => write!(fmt, "#NUM!"), Error::ERROR => write!(fmt, "#ERROR!"), Error::NIMPL => write!(fmt, "#N/IMPL"), Error::SPILL => write!(fmt, "#SPILL!"), Error::CALC => write!(fmt, "#CALC!"), Error::CIRC => write!(fmt, "#CIRC!"), } } } impl Error { pub fn to_localized_error_string(&self, language: &Language) -> String { match self { Error::NULL => language.errors.null.to_string(), Error::REF => language.errors.r#ref.to_string(), Error::NAME => language.errors.name.to_string(), Error::VALUE => language.errors.value.to_string(), Error::DIV => language.errors.div.to_string(), Error::NA => language.errors.na.to_string(), Error::NUM => language.errors.num.to_string(), Error::ERROR => language.errors.error.to_string(), Error::NIMPL => language.errors.nimpl.to_string(), Error::SPILL => language.errors.spill.to_string(), Error::CALC => language.errors.calc.to_string(), Error::CIRC => language.errors.circ.to_string(), } } } pub fn get_error_by_name(name: &str, language: &Language) -> Option { let errors = &language.errors; if name == errors.r#ref { return Some(Error::REF); } else if name == errors.name { return Some(Error::NAME); } else if name == errors.value { return Some(Error::VALUE); } else if name == errors.div { return Some(Error::DIV); } else if name == errors.na { return Some(Error::NA); } else if name == errors.num { return Some(Error::NUM); } else if name == errors.error { return Some(Error::ERROR); } else if name == errors.nimpl { return Some(Error::NIMPL); } else if name == errors.spill { return Some(Error::SPILL); } else if name == errors.calc { return Some(Error::CALC); } else if name == errors.circ { return Some(Error::CIRC); } else if name == errors.null { return Some(Error::NULL); } None } pub fn get_error_by_english_name(name: &str) -> Option { if name == "#REF!" { return Some(Error::REF); } else if name == "#NAME?" { return Some(Error::NAME); } else if name == "#VALUE!" { return Some(Error::VALUE); } else if name == "#DIV/0!" { return Some(Error::DIV); } else if name == "#N/A" { return Some(Error::NA); } else if name == "#NUM!" { return Some(Error::NUM); } else if name == "#ERROR!" { return Some(Error::ERROR); } else if name == "#N/IMPL!" { return Some(Error::NIMPL); } else if name == "#SPILL!" { return Some(Error::SPILL); } else if name == "#CALC!" { return Some(Error::CALC); } else if name == "#CIRC!" { return Some(Error::CIRC); } else if name == "#NULL!" { return Some(Error::NULL); } None } pub fn is_english_error_string(name: &str) -> bool { let names = [ "#REF!", "#NAME?", "#VALUE!", "#DIV/0!", "#N/A", "#NUM!", "#ERROR!", "#N/IMPL!", "#SPILL!", "#CALC!", "#CIRC!", "#NULL!", ]; names.contains(&name) } #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] pub enum TableSpecifier { All, Data, Headers, ThisRow, Totals, } #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] pub enum TableReference { ColumnReference(String), RangeReference((String, String)), } #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] pub enum TokenType { Illegal(LexerError), EOF, Ident(String), // abc123 String(String), // "A season" Number(f64), // 123.4 Boolean(bool), // TRUE | FALSE Error(Error), // #VALUE! Compare(OpCompare), // <,>, ... Addition(OpSum), // +,- Product(OpProduct), // *,/ Power, // ^ LeftParenthesis, // ( RightParenthesis, // ) Colon, // : Semicolon, // ; LeftBracket, // [ RightBracket, // ] LeftBrace, // { RightBrace, // } Comma, // , Bang, // ! Percent, // % And, // & At, // @ Reference { sheet: Option, row: i32, column: i32, absolute_column: bool, absolute_row: bool, }, Range { sheet: Option, left: ParsedReference, right: ParsedReference, }, StructuredReference { table_name: String, specifier: Option, table_reference: Option, }, }