Skip to main content

ironcalc_base/expressions/
token.rs

1use std::fmt;
2
3use bitcode::{Decode, Encode};
4use serde::{Deserialize, Serialize};
5
6use crate::language::Language;
7
8use super::{lexer::LexerError, types::ParsedReference};
9
10#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
11pub enum OpCompare {
12    LessThan,
13    GreaterThan,
14    Equal,
15    LessOrEqualThan,
16    GreaterOrEqualThan,
17    NonEqual,
18}
19
20impl fmt::Display for OpCompare {
21    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
22        match self {
23            OpCompare::LessThan => write!(fmt, "<"),
24            OpCompare::GreaterThan => write!(fmt, ">"),
25            OpCompare::Equal => write!(fmt, "="),
26            OpCompare::LessOrEqualThan => write!(fmt, "<="),
27            OpCompare::GreaterOrEqualThan => write!(fmt, ">="),
28            OpCompare::NonEqual => write!(fmt, "<>"),
29        }
30    }
31}
32
33#[derive(Debug, PartialEq, Eq, Clone)]
34pub enum OpUnary {
35    Minus,
36    Percentage,
37}
38
39impl fmt::Display for OpUnary {
40    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
41        match self {
42            OpUnary::Minus => write!(fmt, "-"),
43            OpUnary::Percentage => write!(fmt, "%"),
44        }
45    }
46}
47
48#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
49pub enum OpSum {
50    Add,
51    Minus,
52}
53
54impl fmt::Display for OpSum {
55    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
56        match self {
57            OpSum::Add => write!(fmt, "+"),
58            OpSum::Minus => write!(fmt, "-"),
59        }
60    }
61}
62
63#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
64pub enum OpProduct {
65    Times,
66    Divide,
67}
68
69impl fmt::Display for OpProduct {
70    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
71        match self {
72            OpProduct::Times => write!(fmt, "*"),
73            OpProduct::Divide => write!(fmt, "/"),
74        }
75    }
76}
77
78/// List of `errors`
79/// Note that "#ERROR!" and "#N/IMPL!" are not part of the xlsx standard
80///  * "#ERROR!" means there was an error processing the formula (for instance "=A1+")
81///  * "#N/IMPL!" means the formula or feature in Excel but has not been implemented in IronCalc
82///    Note that they are serialized/deserialized by index
83#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Eq, Clone)]
84pub enum Error {
85    REF,
86    NAME,
87    VALUE,
88    DIV,
89    NA,
90    NUM,
91    ERROR,
92    NIMPL,
93    SPILL,
94    CALC,
95    CIRC,
96    NULL,
97}
98
99impl fmt::Display for Error {
100    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
101        match self {
102            Error::NULL => write!(fmt, "#NULL!"),
103            Error::REF => write!(fmt, "#REF!"),
104            Error::NAME => write!(fmt, "#NAME?"),
105            Error::VALUE => write!(fmt, "#VALUE!"),
106            Error::DIV => write!(fmt, "#DIV/0!"),
107            Error::NA => write!(fmt, "#N/A"),
108            Error::NUM => write!(fmt, "#NUM!"),
109            Error::ERROR => write!(fmt, "#ERROR!"),
110            Error::NIMPL => write!(fmt, "#N/IMPL"),
111            Error::SPILL => write!(fmt, "#SPILL!"),
112            Error::CALC => write!(fmt, "#CALC!"),
113            Error::CIRC => write!(fmt, "#CIRC!"),
114        }
115    }
116}
117impl Error {
118    pub fn to_localized_error_string(&self, language: &Language) -> String {
119        match self {
120            Error::NULL => language.errors.null.to_string(),
121            Error::REF => language.errors.r#ref.to_string(),
122            Error::NAME => language.errors.name.to_string(),
123            Error::VALUE => language.errors.value.to_string(),
124            Error::DIV => language.errors.div.to_string(),
125            Error::NA => language.errors.na.to_string(),
126            Error::NUM => language.errors.num.to_string(),
127            Error::ERROR => language.errors.error.to_string(),
128            Error::NIMPL => language.errors.nimpl.to_string(),
129            Error::SPILL => language.errors.spill.to_string(),
130            Error::CALC => language.errors.calc.to_string(),
131            Error::CIRC => language.errors.circ.to_string(),
132        }
133    }
134}
135
136pub fn get_error_by_name(name: &str, language: &Language) -> Option<Error> {
137    let errors = &language.errors;
138    if name == errors.r#ref {
139        return Some(Error::REF);
140    } else if name == errors.name {
141        return Some(Error::NAME);
142    } else if name == errors.value {
143        return Some(Error::VALUE);
144    } else if name == errors.div {
145        return Some(Error::DIV);
146    } else if name == errors.na {
147        return Some(Error::NA);
148    } else if name == errors.num {
149        return Some(Error::NUM);
150    } else if name == errors.error {
151        return Some(Error::ERROR);
152    } else if name == errors.nimpl {
153        return Some(Error::NIMPL);
154    } else if name == errors.spill {
155        return Some(Error::SPILL);
156    } else if name == errors.calc {
157        return Some(Error::CALC);
158    } else if name == errors.circ {
159        return Some(Error::CIRC);
160    } else if name == errors.null {
161        return Some(Error::NULL);
162    }
163    None
164}
165
166pub fn get_error_by_english_name(name: &str) -> Option<Error> {
167    if name == "#REF!" {
168        return Some(Error::REF);
169    } else if name == "#NAME?" {
170        return Some(Error::NAME);
171    } else if name == "#VALUE!" {
172        return Some(Error::VALUE);
173    } else if name == "#DIV/0!" {
174        return Some(Error::DIV);
175    } else if name == "#N/A" {
176        return Some(Error::NA);
177    } else if name == "#NUM!" {
178        return Some(Error::NUM);
179    } else if name == "#ERROR!" {
180        return Some(Error::ERROR);
181    } else if name == "#N/IMPL!" {
182        return Some(Error::NIMPL);
183    } else if name == "#SPILL!" {
184        return Some(Error::SPILL);
185    } else if name == "#CALC!" {
186        return Some(Error::CALC);
187    } else if name == "#CIRC!" {
188        return Some(Error::CIRC);
189    } else if name == "#NULL!" {
190        return Some(Error::NULL);
191    }
192    None
193}
194
195pub fn is_english_error_string(name: &str) -> bool {
196    let names = [
197        "#REF!", "#NAME?", "#VALUE!", "#DIV/0!", "#N/A", "#NUM!", "#ERROR!", "#N/IMPL!", "#SPILL!",
198        "#CALC!", "#CIRC!", "#NULL!",
199    ];
200    names.contains(&name)
201}
202
203#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
204pub enum TableSpecifier {
205    All,
206    Data,
207    Headers,
208    ThisRow,
209    Totals,
210}
211
212#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
213pub enum TableReference {
214    ColumnReference(String),
215    RangeReference((String, String)),
216}
217
218#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
219pub enum TokenType {
220    Illegal(LexerError),
221    EOF,
222    Ident(String),      // abc123
223    String(String),     // "A season"
224    Number(f64),        // 123.4
225    Boolean(bool),      // TRUE | FALSE
226    Error(Error),       // #VALUE!
227    Compare(OpCompare), // <,>, ...
228    Addition(OpSum),    // +,-
229    Product(OpProduct), // *,/
230    Power,              // ^
231    LeftParenthesis,    // (
232    RightParenthesis,   // )
233    Colon,              // :
234    Semicolon,          // ;
235    LeftBracket,        // [
236    RightBracket,       // ]
237    LeftBrace,          // {
238    RightBrace,         // }
239    Comma,              // ,
240    Bang,               // !
241    Percent,            // %
242    And,                // &
243    At,                 // @
244    Spill,              // #
245    Backslash,          // \
246    Reference {
247        sheet: Option<String>,
248        row: i32,
249        column: i32,
250        absolute_column: bool,
251        absolute_row: bool,
252    },
253    Range {
254        sheet: Option<String>,
255        left: ParsedReference,
256        right: ParsedReference,
257    },
258    StructuredReference {
259        table_name: String,
260        specifier: Option<TableSpecifier>,
261        table_reference: Option<TableReference>,
262    },
263}