1use crate::{
2 parser::{
3 ast::{Literal, Prefix, Infix, Expr},
4 parse_str
5 },
6 function::*,
7 workbook::Book,
8 evaluate::value::Value,
9 reference::Reference,
10 errors::Error,
11};
12
13pub mod value;
14
15pub fn evaluate_str(s: &str) -> Result<Value, Error> {
16 let expr = parse_str(s)?;
17 evaluate_expr(expr)
18}
19
20pub fn evaluate_expr(expr: Expr) -> Result<Value, Error> {
21 let value = match expr {
22 Expr::Func {name, args} => {
23 let arg_values: Vec<Value> = args.into_iter().map(|x| evaluate_expr(x).unwrap()).collect::<Vec<Value>>();
24 get_function_value(&name, arg_values)?
25 },
26 Expr::Literal(lit) => {
27 match lit {
28 Literal::Number(f) => {
29 if f.is_nan() {
30 Value::from(0.0)
31 } else {
32 Value::from(f)
33 }
34 }
35 Literal::Boolean(b) => Value::from(b),
36 Literal::Text(s) => Value::from(s)
37 }
38 },
39 Expr::Prefix(p, box_expr) => {
40 match p {
41 Prefix::Plus => Value::from(evaluate_expr(*box_expr)?.as_num().abs()),
42 Prefix::Minus => evaluate_expr(*box_expr)? * Value::from(-1.0)
43 }
44 },
45 Expr::Infix(i, a, b) => {
46 match i {
47 Infix::Plus => evaluate_expr(*a)? + evaluate_expr(*b)?,
48 Infix::Minus => evaluate_expr(*a)? - evaluate_expr(*b)?,
49 Infix::Multiply => evaluate_expr(*a)? * evaluate_expr(*b)?,
50 Infix::Divide => evaluate_expr(*a)? / evaluate_expr(*b)?,
51 Infix::Exponent => Exponent {a: evaluate_expr(*a)?, b: evaluate_expr(*b)?}.evaluate(),
52 Infix::NotEqual => Value::from(evaluate_expr(*a)? != evaluate_expr(*b)?),
53 Infix::Equal => Value::from(evaluate_expr(*a)? == evaluate_expr(*b)?),
54 Infix::LessThan => Value::from(evaluate_expr(*a)? < evaluate_expr(*b)?),
55 Infix::LessThanEqual => Value::from(evaluate_expr(*a)? <= evaluate_expr(*b)?),
56 Infix::GreaterThan => Value::from(evaluate_expr(*a)? > evaluate_expr(*b)?),
57 Infix::GreaterThanEqual => Value::from(evaluate_expr(*a)? >= evaluate_expr(*b)?),
58 Infix::Ampersand => {
59 let a = evaluate_expr(*a)?;
60 let b = evaluate_expr(*b)?;
61 let value = if a.is_array() {
62 Value::from(a.as_array().into_iter().map(|x| Value::from(format!("{}{}", x.as_text(), b.as_text()))).collect::<Vec<Value>>())
63 } else if b.is_array() {
64 Value::from(b.as_array().into_iter().map(|x| Value::from(format!("{}{}", a.as_text(), x.as_text()))).collect::<Vec<Value>>())
65 } else {
66 Value::from(format!("{}{}", a.as_text(), b.as_text()))
67 };
68 value
69 },
70 }
71 },
72 Expr::Array(x) => Value::Array(x.into_iter().map(|x| evaluate_expr(x).unwrap()).collect::<Vec<Value>>()),
73 Expr::Error(err) => Value::Error(err),
74 _ => panic!("Expression {:?} does not convert to a value.", expr)
75 };
76 Ok(value)
77}
78
79pub fn offset_expr(args: Vec<Expr>, book: &Book, debug: bool) -> Result<Expr, Error> {
80 if let Expr::Reference { sheet, reference } = args.get(0).unwrap() {
81 let rows = evaluate_expr_with_context(args.get(1).unwrap().clone(), book, debug)?;
82 let cols = evaluate_expr_with_context(args.get(2).unwrap().clone(), book, debug)?;
83 let height = args.get(3);
84 let height_opt: Option<i32> = height.map(|h| {
85 evaluate_expr_with_context(h.clone(), book, debug).unwrap().as_num() as i32
86 });
87 let width = args.get(4);
88 let width_opt: Option<i32> = width.map(|w| {
89 evaluate_expr_with_context(w.clone(), book, debug).unwrap().as_num() as i32
90 });
91 println!("{:?},{:?},{:?},{:?}", rows, cols, height_opt, width_opt);
92 let new_reference = offset_reference(&mut Reference::from(reference.as_str()), rows.as_num() as i32, cols.as_num() as i32, height_opt, width_opt);
93 Ok(Expr::Reference { sheet: sheet.clone(), reference: new_reference.to_string() })
94 } else {
95 panic!("Offset must have a reference.")
96 }
97}
98
99pub fn ensure_non_range(value: Value) -> Value {
100 if let Value::Range { sheet: _, reference: _, value } = value {
101 if let Some(value) = value {
102 return *value;
103 } else {
104 panic!("Value::Range is missing a value to return")
105 }
106 } else {
107 return value;
108 }
109}
110
111pub fn evaluate_expr_with_context(expr: Expr, book: &Book, debug: bool) -> Result<Value, Error> {
112 let value = match expr.clone() {
113 Expr::Reference { ref sheet, ref reference } => {
114 let range_value: Option<Box<Value>> = match book.resolve_ref(expr.clone()) {
115 Ok(arr2) => Some(Box::new(Value::from(arr2))),
116 _ => None
117 };
118 Value::Range { sheet: sheet.clone(), reference: Reference::from(reference.clone()), value: range_value }
119 },
120 Expr::Func {name, args} => {
121 match name.as_str() {
122 "OFFSET" => {
123 let offset_value: Value = offset(args, book, debug)?;
124 match offset_value {
125 Value::Range {sheet: _, reference: _, value } => {
126 Value::from(value.unwrap().as_array2())
127 },
128 _ => unreachable!()
129 }
130 },
131 "INDEX" => {
132 index(args, book, debug)?
133 },
134 c => {
135 let arg_values: Vec<Value> = args.into_iter().map(|x| ensure_non_range(evaluate_expr_with_context(x, book, debug).unwrap())).collect::<Vec<Value>>();
136 get_function_value(c, arg_values)?
137 }
138 }
139 },
140 Expr::Literal(lit) => {
141 match lit {
142 Literal::Number(f) => Value::from(f),
143 Literal::Boolean(b) => Value::from(b),
144 Literal::Text(s) => Value::from(s)
145 }
146 },
147 Expr::Prefix(p, box_expr) => {
148 match p {
149 Prefix::Plus => Value::from(ensure_non_range(evaluate_expr_with_context(*box_expr, book, debug)?).as_num().abs()),
150 Prefix::Minus => ensure_non_range(evaluate_expr_with_context(*box_expr, book, debug)?) * Value::from(-1.0)
151 }
152 },
153 Expr::Infix(i, a, b) => {
154 match i {
155 Infix::Plus => ensure_non_range(evaluate_expr_with_context(*a, book, debug)?).ensure_single() + ensure_non_range(evaluate_expr_with_context(*b, book, debug)?).ensure_single(),
156 Infix::Minus => ensure_non_range(evaluate_expr_with_context(*a, book, debug)?).ensure_single() - ensure_non_range(evaluate_expr_with_context(*b, book, debug)?).ensure_single(),
157 Infix::Multiply => ensure_non_range(evaluate_expr_with_context(*a, book, debug)?).ensure_single() * ensure_non_range(evaluate_expr_with_context(*b, book, debug)?).ensure_single(),
158 Infix::Divide => ensure_non_range(evaluate_expr_with_context(*a, book, debug)?).ensure_single() / ensure_non_range(evaluate_expr_with_context(*b, book, debug)?).ensure_single(),
159 Infix::Exponent => Exponent {a: ensure_non_range(evaluate_expr_with_context(*a, book, debug)?).ensure_single(), b: ensure_non_range(evaluate_expr_with_context(*b, book, debug)?).ensure_single()}.evaluate(),
160 Infix::NotEqual => Value::from(ensure_non_range(evaluate_expr_with_context(*a, book, debug)?).ensure_single() != ensure_non_range(evaluate_expr_with_context(*b, book, debug)?).ensure_single()),
161 Infix::Equal => Value::from(ensure_non_range(evaluate_expr_with_context(*a, book, debug)?).ensure_single() == ensure_non_range(evaluate_expr_with_context(*b, book, debug)?).ensure_single()),
162 Infix::LessThan => Value::from(ensure_non_range(evaluate_expr_with_context(*a, book, debug)?).ensure_single() < ensure_non_range(evaluate_expr_with_context(*b, book, debug)?).ensure_single()),
163 Infix::LessThanEqual => Value::from(ensure_non_range(evaluate_expr_with_context(*a, book, debug)?).ensure_single() <= ensure_non_range(evaluate_expr_with_context(*b, book, debug)?).ensure_single()),
164 Infix::GreaterThan => Value::from(ensure_non_range(evaluate_expr_with_context(*a, book, debug)?).ensure_single() > ensure_non_range(evaluate_expr_with_context(*b, book, debug)?).ensure_single()),
165 Infix::GreaterThanEqual => Value::from(ensure_non_range(evaluate_expr_with_context(*a, book, debug)?).ensure_single() >= ensure_non_range(evaluate_expr_with_context(*b, book, debug)?).ensure_single()),
166 Infix::Ampersand => {
167 let a = evaluate_expr_with_context(*a, book, debug)?;
168 let b = evaluate_expr_with_context(*b, book, debug)?;
169 let value = if a.is_array() {
170 Value::from(a.as_array().into_iter().map(|x| Value::from(format!("{}{}", x.as_text(), b.as_text()))).collect::<Vec<Value>>())
171 } else if b.is_array() {
172 Value::from(b.as_array().into_iter().map(|x| Value::from(format!("{}{}", a.as_text(), x.as_text()))).collect::<Vec<Value>>())
173 } else {
174 Value::from(format!("{}{}", a.as_text(), b.as_text()))
175 };
176 value
177 },
178 }
179 },
180 Expr::Array(x) => Value::Array(x.into_iter().map(|e| ensure_non_range(evaluate_expr_with_context(e, book, debug).unwrap())).collect::<Vec<Value>>()),
181 _ => panic!("Expression {:?} does not convert to a value.", expr)
182 };
183 if debug {
184 match expr.clone() {
185 Expr::Literal(_) | Expr::Reference { sheet: _, reference: _} => {},
186 _ => {
187 println!("{} => {:?}", expr, value.clone());
188 }
189 }
190 }
191 Ok(value)
192}
193
194#[cfg(test)]
195mod tests {
196 use crate::evaluate::evaluate_str;
197 use crate::evaluate::value::Value;
198 use crate::errors::Error;
199
200 #[test]
201 fn test_op_codes() -> Result<(), Error> {
202 assert_eq!(evaluate_str(" 1 + 1 ")?, Value::from(2.0));
203 assert_eq!(evaluate_str(" 1 - 1 ")?, Value::from(0.0));
204 assert_eq!(evaluate_str(" 2 * 2 ")?, Value::from(4.0));
205 assert_eq!(evaluate_str(" (2 + 1) * 2 ")?, Value::from(6.0));
206 assert_eq!(evaluate_str(" 8 / 4 ")?, Value::from(2.0));
207 assert_eq!(evaluate_str(" 8^2 ")?, Value::from(64.0));
208 Ok(())
209 }
210
211 #[test]
212 fn test_conditionals() -> Result<(), Error> {
213 assert_eq!(evaluate_str(" 1=1 ")?, Value::from(true));
214 Ok(())
215 }
216
217 #[test]
218 fn test_infix_precedence() -> Result<(), Error> {
219 assert_eq!(evaluate_str(" -(1+1)-2 ")?, Value::from(-4.0));
220 Ok(())
221 }
222
223 #[test]
224 fn test_formula() -> Result<(), Error> {
225 assert_eq!(evaluate_str(" SUM(1, 1) ")?, Value::from(2.0));
226 assert_eq!(evaluate_str(" SUM(SUM(1, 2), 1) ")?, Value::from(4.0));
227 Ok(())
228 }
229}
230