excel_lib/evaluate/
mod.rs

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