1use std::borrow::Cow;
22use std::cell::Cell as Counter;
23use std::cmp::Ordering;
24use std::collections::BTreeMap;
25
26use crate::intrinsics::fold;
27use crate::rows::quoted;
28use crate::sheet::Workbook;
29
30use super::dense::Dense;
31use super::formula::{self, BinOp, Expr, RefExpr};
32use super::graph::{areas_at, cells_in, Area, Areas, CellId, Extent};
33use super::value::{ErrorKind, Value};
34
35#[derive(Clone, Debug, PartialEq, Eq)]
37pub enum Reason {
38 Function(String),
40 Construct(String),
42 Cycle,
44}
45
46impl Reason {
47 pub fn spell(&self) -> String {
49 match self {
50 Reason::Function(name) | Reason::Construct(name) => {
51 format!("(not-computed {})", quoted(name))
52 }
53 Reason::Cycle => "(not-computed cycle)".to_string(),
54 }
55 }
56}
57
58#[derive(Clone, Debug, PartialEq)]
60pub enum Computed {
61 Value(Value),
62 NotComputed(Reason),
63}
64
65impl Computed {
66 pub fn spell(&self) -> String {
68 match self {
69 Computed::Value(v) => v.spell(),
70 Computed::NotComputed(r) => r.spell(),
71 }
72 }
73}
74
75#[derive(Clone, Debug, PartialEq)]
79pub enum Arg<'e> {
80 Scalar(Value),
81 Area {
82 areas: Areas,
83 written: Cow<'e, str>,
87 moved: (i64, i64),
91 },
92}
93
94impl Arg<'_> {
95 pub fn into_owned(self) -> Arg<'static> {
98 match self {
99 Arg::Scalar(v) => Arg::Scalar(v),
100 Arg::Area {
101 areas,
102 written,
103 moved,
104 } => Arg::Area {
105 areas,
106 written: Cow::Owned(written.into_owned()),
107 moved,
108 },
109 }
110 }
111}
112
113pub trait Env {
115 fn model(&self) -> &Workbook;
117 fn here(&self) -> CellId;
119 fn read(&self, id: CellId) -> Result<Value, Reason>;
123 fn extent(&self, sheet: usize) -> Extent;
125 fn name(&self, name: &str, scope: Option<usize>, home: usize) -> Option<&str>;
128 fn dense(&self, _sheet: usize) -> Option<&Dense> {
136 None
137 }
138
139 fn enter(&self, _id: CellId) {}
145}
146
147pub type Strict = fn(&Ctx<'_>, &[Arg<'_>]) -> Result<Value, Reason>;
149
150pub type Form = for<'e> fn(&Ctx<'_>, &'e [Expr]) -> Result<Arg<'e>, Reason>;
153
154#[derive(Clone, Copy, Debug, PartialEq, Eq)]
163pub(crate) enum Known {
164 If,
166 Sum,
168 Min,
169 Max,
170 And,
172 Or,
173 Not,
175 Abs,
177 Int,
178 Sin,
179 Mod,
181 Row,
183 Column,
184 Choose,
186}
187
188#[derive(Default)]
195pub struct Library {
196 strict: BTreeMap<String, (Strict, Option<Known>)>,
199 forms: BTreeMap<String, (Form, Option<Known>)>,
202}
203
204impl Library {
205 pub fn empty() -> Library {
207 Library::default()
208 }
209
210 pub fn register(&mut self, name: &str, f: Strict) {
213 let key = name.to_ascii_uppercase();
214 self.forms.remove(&key);
215 self.strict.insert(key, (f, None));
216 }
217
218 pub fn register_form(&mut self, name: &str, f: Form) {
220 let key = name.to_ascii_uppercase();
221 self.strict.remove(&key);
222 self.forms.insert(key, (f, None));
223 }
224
225 pub(crate) fn register_known(&mut self, name: &str, f: Form, known: Known) {
228 let key = name.to_ascii_uppercase();
229 self.strict.remove(&key);
230 self.forms.insert(key, (f, Some(known)));
231 }
232
233 pub(crate) fn register_known_strict(&mut self, name: &str, f: Strict, known: Known) {
237 let key = name.to_ascii_uppercase();
238 self.forms.remove(&key);
239 self.strict.insert(key, (f, Some(known)));
240 }
241
242 pub(crate) fn known(&self, name: &str) -> Option<Known> {
245 let key = key(name);
246 match self.forms.get(&*key) {
247 Some(&(_, known)) => known,
248 None => self.strict.get(&*key).and_then(|&(_, known)| known),
249 }
250 }
251
252 pub fn strict(&self, name: &str) -> Option<Strict> {
254 self.strict.get(&*key(name)).map(|&(f, _)| f)
255 }
256
257 pub fn form(&self, name: &str) -> Option<Form> {
259 self.forms.get(&*key(name)).map(|&(f, _)| f)
260 }
261
262 pub fn has(&self, name: &str) -> bool {
264 let wanted = key(name);
265 self.strict.contains_key(&*wanted) || self.forms.contains_key(&*wanted)
266 }
267
268 pub fn names(&self) -> Vec<&str> {
270 let mut names: Vec<&str> = self
271 .strict
272 .keys()
273 .chain(self.forms.keys())
274 .map(String::as_str)
275 .collect();
276 names.sort_unstable();
277 names
278 }
279
280 pub fn len(&self) -> usize {
282 self.strict.len() + self.forms.len()
283 }
284
285 pub fn is_empty(&self) -> bool {
287 self.len() == 0
288 }
289}
290
291fn key(name: &str) -> Cow<'_, str> {
296 if name.bytes().any(|b| b.is_ascii_lowercase()) {
297 Cow::Owned(name.to_ascii_uppercase())
298 } else {
299 Cow::Borrowed(name)
300 }
301}
302
303const NAME_DEPTH: u32 = 16;
305
306pub struct Ctx<'a> {
308 pub env: &'a dyn Env,
309 pub lib: &'a Library,
310 depth: Counter<u32>,
311 offset: Counter<(i64, i64)>,
315}
316
317impl<'a> Ctx<'a> {
318 pub fn new(env: &'a dyn Env, lib: &'a Library) -> Ctx<'a> {
319 Ctx::at(env, lib, 0, 0)
320 }
321
322 pub fn at(env: &'a dyn Env, lib: &'a Library, d_row: i64, d_col: i64) -> Ctx<'a> {
328 Ctx {
329 env,
330 lib,
331 depth: Counter::new(0),
332 offset: Counter::new((d_row, d_col)),
333 }
334 }
335
336 pub fn eval<'e>(&self, e: &'e Expr) -> Result<Arg<'e>, Reason> {
338 match e {
339 Expr::Number(v) => Ok(Arg::Scalar(Value::Number(*v))),
340 Expr::Text(t) => Ok(Arg::Scalar(Value::Text(t.clone()))),
341 Expr::Bool(b) => Ok(Arg::Scalar(Value::Bool(*b))),
342 Expr::Error(k) => Ok(Arg::Scalar(Value::Error(*k))),
343 Expr::Empty => Ok(Arg::Scalar(Value::Empty)),
344 Expr::Ref(r) => self.reference(r),
345 Expr::Name { name, sheet } => self.named(name, sheet.as_deref()),
346 Expr::Call(name, args) => self.call(name, args),
347 Expr::Neg(x) => {
348 let v = self.scalar(x)?;
349 Ok(Arg::Scalar(match v.number() {
350 Ok(n) => finite(-n),
351 Err(k) => Value::Error(k),
352 }))
353 }
354 Expr::Pos(x) => self.eval(x),
356 Expr::Percent(x) => {
357 let v = self.scalar(x)?;
358 Ok(Arg::Scalar(match v.number() {
359 Ok(n) => finite(n / 100.0),
360 Err(k) => Value::Error(k),
361 }))
362 }
363 Expr::Binary(op, l, r) if !matches!(**l, Expr::Binary(..)) => {
366 let a = self.scalar(l)?;
367 let b = self.scalar(r)?;
368 Ok(Arg::Scalar(binary(*op, &a, &b)))
369 }
370 Expr::Binary(..) => self.chain(e),
371 }
372 }
373
374 fn chain<'e>(&self, e: &'e Expr) -> Result<Arg<'e>, Reason> {
382 const NEAR: usize = 16;
383 let mut near: [(BinOp, &Expr); NEAR] = [(BinOp::Add, e); NEAR];
384 let mut far: Vec<(BinOp, &Expr)> = Vec::new();
385 let mut links = 0;
386 let mut left = e;
387 while let Expr::Binary(op, l, r) = left {
388 if links < NEAR {
389 near[links] = (*op, r);
390 } else {
391 far.push((*op, r));
392 }
393 links += 1;
394 left = l;
395 }
396 let mut acc = self.scalar(left)?;
397 for i in (0..links).rev() {
398 let (op, r) = if i < NEAR { near[i] } else { far[i - NEAR] };
399 let b = self.scalar(r)?;
400 acc = binary(op, &acc, &b);
401 }
402 Ok(Arg::Scalar(acc))
403 }
404
405 pub fn scalar(&self, e: &Expr) -> Result<Value, Reason> {
408 let arg = self.eval(e)?;
409 self.one(&arg)
410 }
411
412 pub fn one(&self, arg: &Arg<'_>) -> Result<Value, Reason> {
414 match arg {
415 Arg::Scalar(v) => Ok(v.clone()),
416 Arg::Area {
417 areas,
418 written,
419 moved,
420 } => match &areas[..] {
421 [a] if a.is_cell() => self.env.read((a.sheet, a.top, a.left)),
422 _ if *moved == (0, 0) => Err(Reason::Construct(written.to_string())),
423 _ => Err(Reason::Construct(crate::refers::shift_a1_references(
425 written, moved.0, moved.1,
426 ))),
427 },
428 }
429 }
430
431 pub fn truth(&self, e: &Expr) -> Result<Result<bool, ErrorKind>, Reason> {
439 Ok(self.scalar(e)?.truth())
440 }
441
442 pub fn truth_arg(&self, arg: &Arg<'_>) -> Result<Result<bool, ErrorKind>, Reason> {
444 Ok(self.one(arg)?.truth())
445 }
446
447 pub fn each<F>(&self, areas: &[Area], mut f: F) -> Result<(), Reason>
454 where
455 F: FnMut(Value) -> Result<(), Reason>,
456 {
457 let model = self.env.model();
458 for a in areas {
459 if let Some(kept) = self.env.dense(a.sheet) {
460 kept.each(a, &mut f)?;
461 continue;
462 }
463 let Some(sheet) = model.sheets.get(a.sheet) else {
464 continue;
465 };
466 for ((row, col), _) in cells_in(sheet, self.env.extent(a.sheet), a) {
467 let v = self.env.read((a.sheet, row, col))?;
468 if v != Value::Empty {
469 f(v)?;
470 }
471 }
472 }
473 Ok(())
474 }
475
476 pub(super) fn reference<'e>(&self, r: &'e RefExpr) -> Result<Arg<'e>, Reason> {
477 let home = self.env.here().0;
478 let (d_row, d_col) = self.offset.get();
479 match areas_at(self.env.model(), home, r, d_row, d_col) {
480 Ok(areas) => Ok(Arg::Area {
481 areas,
482 written: Cow::Borrowed(&r.written),
483 moved: (d_row, d_col),
484 }),
485 Err(k) => Ok(Arg::Scalar(Value::Error(k))),
486 }
487 }
488
489 fn named(&self, name: &str, sheet: Option<&str>) -> Result<Arg<'static>, Reason> {
493 let model = self.env.model();
494 let home = self.env.here().0;
495 let scope = match sheet {
496 None => None,
497 Some(s) => match model.find_sheet(s) {
498 Some(i) => Some(i),
499 None => return Ok(Arg::Scalar(Value::Error(ErrorKind::Ref))),
500 },
501 };
502 let Some(text) = self.env.name(name, scope, home) else {
503 return Ok(Arg::Scalar(Value::Error(ErrorKind::Name)));
504 };
505 if self.depth.get() >= NAME_DEPTH {
506 return Ok(Arg::Scalar(Value::Error(ErrorKind::Name)));
507 }
508 let parsed = formula::parse(text).map_err(Reason::Construct)?;
509 let offset = self.offset.replace((0, 0));
511 self.depth.set(self.depth.get() + 1);
512 let result = self.eval(&parsed).map(Arg::into_owned);
513 self.depth.set(self.depth.get() - 1);
514 self.offset.set(offset);
515 result
516 }
517
518 fn call<'e>(&self, name: &str, args: &'e [Expr]) -> Result<Arg<'e>, Reason> {
519 if let Some(form) = self.lib.form(name) {
520 return form(self, args);
521 }
522 if let Some(f) = self.lib.strict(name) {
523 return match args {
529 [a] => self.strict_one(f, a),
530 [a, b] => self.strict_two(f, a, b),
531 _ => {
532 let mut values = Vec::with_capacity(args.len());
533 for a in args {
534 values.push(self.eval(a)?);
535 }
536 f(self, &values)
537 }
538 }
539 .map(Arg::Scalar);
540 }
541 Err(Reason::Function(name.to_string()))
542 }
543
544 fn strict_one(&self, f: Strict, a: &Expr) -> Result<Value, Reason> {
546 let x = self.eval(a)?;
547 f(self, std::slice::from_ref(&x))
548 }
549
550 fn strict_two(&self, f: Strict, a: &Expr, b: &Expr) -> Result<Value, Reason> {
552 let pair = [self.eval(a)?, self.eval(b)?];
553 f(self, &pair)
554 }
555}
556
557pub fn finite(v: f64) -> Value {
559 if v == 0.0 {
560 Value::Number(0.0)
562 } else if v.is_finite() {
563 Value::Number(v)
564 } else {
565 Value::Error(ErrorKind::Num)
566 }
567}
568
569pub fn binary(op: BinOp, a: &Value, b: &Value) -> Value {
576 if let Value::Error(k) = a {
577 return Value::Error(*k);
578 }
579 if let Value::Error(k) = b {
580 return Value::Error(*k);
581 }
582 match op {
583 BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Pow => {
584 let x = match a.number() {
585 Ok(n) => n,
586 Err(k) => return Value::Error(k),
587 };
588 let y = match b.number() {
589 Ok(n) => n,
590 Err(k) => return Value::Error(k),
591 };
592 arithmetic(op, x, y)
593 }
594 BinOp::Concat => match (a.text(), b.text()) {
595 (Ok(s), Ok(t)) => Value::Text(s + &t),
596 (Err(k), _) | (_, Err(k)) => Value::Error(k),
597 },
598 _ => Value::Bool(compares(op, compare(a, b))),
599 }
600}
601
602#[inline]
604pub(crate) fn arithmetic(op: BinOp, x: f64, y: f64) -> Value {
605 match op {
606 BinOp::Add => finite(x + y),
607 BinOp::Sub => finite(x - y),
608 BinOp::Mul => finite(x * y),
609 BinOp::Div => {
610 if y == 0.0 {
611 Value::Error(ErrorKind::Div0)
612 } else {
613 finite(x / y)
614 }
615 }
616 _ => power(x, y),
617 }
618}
619
620#[inline]
622pub(crate) fn compares(op: BinOp, ordering: Ordering) -> bool {
623 match op {
624 BinOp::Eq => ordering == Ordering::Equal,
625 BinOp::Ne => ordering != Ordering::Equal,
626 BinOp::Lt => ordering == Ordering::Less,
627 BinOp::Gt => ordering == Ordering::Greater,
628 BinOp::Le => ordering != Ordering::Greater,
629 _ => ordering != Ordering::Less,
630 }
631}
632
633#[inline]
635pub(crate) fn compare_numbers(x: f64, y: f64) -> Ordering {
636 x.partial_cmp(&y).unwrap_or(Ordering::Equal)
637}
638
639fn power(x: f64, y: f64) -> Value {
642 if x == 0.0 && y == 0.0 {
643 return Value::Error(ErrorKind::Num);
644 }
645 if x == 0.0 && y < 0.0 {
646 return Value::Error(ErrorKind::Div0);
647 }
648 finite(x.powf(y))
649}
650
651pub fn compare(a: &Value, b: &Value) -> Ordering {
655 use Value::*;
656 match (a, b) {
657 (Empty, Empty) => Ordering::Equal,
658 (Empty, Number(y)) => 0.0f64.partial_cmp(y).unwrap_or(Ordering::Equal),
659 (Number(x), Empty) => x.partial_cmp(&0.0).unwrap_or(Ordering::Equal),
660 (Empty, Text(t)) => {
661 if t.is_empty() {
662 Ordering::Equal
663 } else {
664 Ordering::Less
665 }
666 }
667 (Text(t), Empty) => {
668 if t.is_empty() {
669 Ordering::Equal
670 } else {
671 Ordering::Greater
672 }
673 }
674 (Empty, Bool(y)) => false.cmp(y),
675 (Bool(x), Empty) => x.cmp(&false),
676 (Number(x), Number(y)) => compare_numbers(*x, *y),
677 (Text(x), Text(y)) => fold(x).cmp(&fold(y)),
678 (Bool(x), Bool(y)) => x.cmp(y),
679 _ => rank(a).cmp(&rank(b)),
680 }
681}
682
683fn rank(v: &Value) -> u8 {
684 match v {
685 Value::Number(_) | Value::Empty => 0,
686 Value::Text(_) => 1,
687 Value::Bool(_) => 2,
688 Value::Error(_) => 3,
689 }
690}
691
692#[cfg(test)]
693mod tests {
694 use super::*;
695
696 #[test]
697 fn operators_coerce_as_excel_does() {
698 let n = |v: f64| Value::Number(v);
699 let t = |s: &str| Value::Text(s.to_string());
700 assert_eq!(binary(BinOp::Add, &t("5"), &n(1.0)), n(6.0));
701 assert_eq!(
702 binary(BinOp::Add, &t("x"), &n(1.0)),
703 Value::Error(ErrorKind::Value)
704 );
705 assert_eq!(binary(BinOp::Mul, &Value::Bool(true), &n(3.0)), n(3.0));
706 assert_eq!(binary(BinOp::Add, &Value::Empty, &n(1.0)), n(1.0));
707 assert_eq!(
708 binary(BinOp::Div, &n(1.0), &n(0.0)),
709 Value::Error(ErrorKind::Div0)
710 );
711 assert_eq!(
712 binary(BinOp::Div, &n(1.0), &Value::Empty),
713 Value::Error(ErrorKind::Div0)
714 );
715 assert_eq!(
716 binary(BinOp::Pow, &n(0.0), &n(0.0)),
717 Value::Error(ErrorKind::Num)
718 );
719 assert_eq!(
720 binary(BinOp::Pow, &n(0.0), &n(-1.0)),
721 Value::Error(ErrorKind::Div0)
722 );
723 assert_eq!(
724 binary(BinOp::Pow, &n(-8.0), &n(1.0 / 3.0)),
725 Value::Error(ErrorKind::Num)
726 );
727 assert_eq!(binary(BinOp::Pow, &n(2.0), &n(10.0)), n(1024.0));
728 assert_eq!(
729 binary(BinOp::Mul, &n(1e308), &n(10.0)),
730 Value::Error(ErrorKind::Num)
731 );
732 assert_eq!(binary(BinOp::Concat, &n(1.0), &n(2.0)), t("12"));
733 assert_eq!(
734 binary(BinOp::Concat, &Value::Bool(true), &Value::Empty),
735 t("TRUE")
736 );
737 assert_eq!(binary(BinOp::Concat, &n(0.1 + 0.2), &t("")), t("0.3"));
738 assert_eq!(
740 binary(
741 BinOp::Add,
742 &Value::Error(ErrorKind::NA),
743 &Value::Error(ErrorKind::Div0)
744 ),
745 Value::Error(ErrorKind::NA)
746 );
747 }
748
749 #[test]
750 fn comparisons_follow_excel_s_order_of_kinds() {
751 let n = |v: f64| Value::Number(v);
752 let t = |s: &str| Value::Text(s.to_string());
753 let yes = Value::Bool(true);
754 assert_eq!(binary(BinOp::Eq, &t("ABC"), &t("abc")), yes);
755 assert_eq!(binary(BinOp::Lt, &n(1e9), &t("")), yes);
756 assert_eq!(binary(BinOp::Gt, &Value::Bool(false), &t("zzz")), yes);
757 assert_eq!(binary(BinOp::Eq, &Value::Empty, &n(0.0)), yes);
758 assert_eq!(binary(BinOp::Eq, &Value::Empty, &t("")), yes);
759 assert_eq!(binary(BinOp::Eq, &Value::Empty, &Value::Bool(false)), yes);
760 assert_eq!(binary(BinOp::Ne, &n(1.0), &t("1")), yes);
761 assert_eq!(binary(BinOp::Le, &n(2.0), &n(2.0)), yes);
762 assert_eq!(binary(BinOp::Ge, &n(1.0), &n(2.0)), Value::Bool(false));
763 }
764
765 #[test]
766 fn the_library_is_keyed_without_case_and_a_name_holds_one_kind() {
767 let mut lib = Library::empty();
768 fn one(_: &Ctx<'_>, _: &[Arg]) -> Result<Value, Reason> {
769 Ok(Value::Number(1.0))
770 }
771 fn two<'e>(_: &Ctx<'_>, _: &'e [Expr]) -> Result<Arg<'e>, Reason> {
772 Ok(Arg::Scalar(Value::Number(2.0)))
773 }
774 lib.register("one", one);
775 lib.register_form("Two", two);
776 assert!(lib.has("ONE") && lib.has("two"));
777 assert_eq!(lib.names(), vec!["ONE", "TWO"]);
778 assert!(lib.strict("one").is_some() && lib.form("one").is_none());
779 lib.register_form("one", two);
780 assert!(lib.strict("one").is_none() && lib.form("one").is_some());
781 assert_eq!(lib.len(), 2);
782 }
783
784 #[test]
785 fn a_name_is_upper_cased_only_when_that_would_change_it() {
786 fn one(_: &Ctx<'_>, _: &[Arg]) -> Result<Value, Reason> {
790 Ok(Value::Number(1.0))
791 }
792 assert!(matches!(key("SUM"), Cow::Borrowed("SUM")));
793 assert!(matches!(key("ÄRGER"), Cow::Borrowed("ÄRGER")));
794 assert_eq!(key("Sum"), "SUM");
795 assert_eq!(key("ärger"), "äRGER");
796 let mut lib = Library::empty();
797 lib.register("Ärger", one);
798 lib.register("sum", one);
799 assert_eq!(lib.names(), vec!["SUM", "ÄRGER"]);
800 for (name, found) in [
801 ("SUM", true),
802 ("Sum", true),
803 ("sum", true),
804 ("ÄRGER", true),
805 ("Ärger", true),
806 ("ärger", false),
807 ("äRGER", false),
808 ] {
809 assert_eq!(lib.strict(name).is_some(), found, "{name}");
810 assert_eq!(lib.has(name), found, "{name}");
811 assert!(lib.form(name).is_none(), "{name}");
812 }
813 }
814}