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#[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), String(String), Number(f64), Boolean(bool), Error(Error), Compare(OpCompare), Addition(OpSum), Product(OpProduct), Power, LeftParenthesis, RightParenthesis, Colon, Semicolon, LeftBracket, RightBracket, LeftBrace, RightBrace, Comma, Bang, Percent, And, At, Spill, Backslash, 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}