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> {
138 None
139 }
140
141 fn enter(&self, _id: CellId) {}
147}
148
149pub type Strict = fn(&Ctx<'_>, &[Arg<'_>]) -> Result<Value, Reason>;
151
152pub type Form = for<'e> fn(&Ctx<'_>, &'e [Expr]) -> Result<Arg<'e>, Reason>;
155
156#[derive(Clone, Copy, Debug, PartialEq, Eq)]
165pub(crate) enum Known {
166 If,
168 Sum,
170 Min,
171 Max,
172 And,
174 Or,
175 Not,
177 Abs,
179 Int,
180 Sin,
181 Mod,
183 Row,
185 Column,
186 Choose,
188}
189
190#[derive(Default)]
197pub struct Library {
198 strict: BTreeMap<String, (Strict, Option<Known>)>,
201 forms: BTreeMap<String, (Form, Option<Known>)>,
204}
205
206impl Library {
207 pub fn empty() -> Library {
209 Library::default()
210 }
211
212 pub fn register(&mut self, name: &str, f: Strict) {
215 let key = name.to_ascii_uppercase();
216 self.forms.remove(&key);
217 self.strict.insert(key, (f, None));
218 }
219
220 pub fn register_form(&mut self, name: &str, f: Form) {
222 let key = name.to_ascii_uppercase();
223 self.strict.remove(&key);
224 self.forms.insert(key, (f, None));
225 }
226
227 pub(crate) fn register_known(&mut self, name: &str, f: Form, known: Known) {
230 let key = name.to_ascii_uppercase();
231 self.strict.remove(&key);
232 self.forms.insert(key, (f, Some(known)));
233 }
234
235 pub(crate) fn register_known_strict(&mut self, name: &str, f: Strict, known: Known) {
239 let key = name.to_ascii_uppercase();
240 self.forms.remove(&key);
241 self.strict.insert(key, (f, Some(known)));
242 }
243
244 pub(crate) fn known(&self, name: &str) -> Option<Known> {
247 let key = key(name);
248 match self.forms.get(&*key) {
249 Some(&(_, known)) => known,
250 None => self.strict.get(&*key).and_then(|&(_, known)| known),
251 }
252 }
253
254 pub fn strict(&self, name: &str) -> Option<Strict> {
256 self.strict.get(&*key(name)).map(|&(f, _)| f)
257 }
258
259 pub fn form(&self, name: &str) -> Option<Form> {
261 self.forms.get(&*key(name)).map(|&(f, _)| f)
262 }
263
264 pub fn has(&self, name: &str) -> bool {
266 let wanted = key(name);
267 self.strict.contains_key(&*wanted) || self.forms.contains_key(&*wanted)
268 }
269
270 pub fn names(&self) -> Vec<&str> {
272 let mut names: Vec<&str> = self
273 .strict
274 .keys()
275 .chain(self.forms.keys())
276 .map(String::as_str)
277 .collect();
278 names.sort_unstable();
279 names
280 }
281
282 pub fn len(&self) -> usize {
284 self.strict.len() + self.forms.len()
285 }
286
287 pub fn is_empty(&self) -> bool {
289 self.len() == 0
290 }
291}
292
293fn key(name: &str) -> Cow<'_, str> {
298 if name.bytes().any(|b| b.is_ascii_lowercase()) {
299 Cow::Owned(name.to_ascii_uppercase())
300 } else {
301 Cow::Borrowed(name)
302 }
303}
304
305const NAME_DEPTH: u32 = 16;
307
308pub struct Ctx<'a> {
310 pub env: &'a dyn Env,
311 pub lib: &'a Library,
312 depth: Counter<u32>,
313 offset: Counter<(i64, i64)>,
317}
318
319impl<'a> Ctx<'a> {
320 pub fn new(env: &'a dyn Env, lib: &'a Library) -> Ctx<'a> {
321 Ctx::at(env, lib, 0, 0)
322 }
323
324 pub fn at(env: &'a dyn Env, lib: &'a Library, d_row: i64, d_col: i64) -> Ctx<'a> {
330 Ctx {
331 env,
332 lib,
333 depth: Counter::new(0),
334 offset: Counter::new((d_row, d_col)),
335 }
336 }
337
338 pub fn eval<'e>(&self, e: &'e Expr) -> Result<Arg<'e>, Reason> {
340 match e {
341 Expr::Number(v) => Ok(Arg::Scalar(Value::Number(*v))),
342 Expr::Text(t) => Ok(Arg::Scalar(Value::Text(t.clone()))),
343 Expr::Bool(b) => Ok(Arg::Scalar(Value::Bool(*b))),
344 Expr::Error(k) => Ok(Arg::Scalar(Value::Error(*k))),
345 Expr::Empty => Ok(Arg::Scalar(Value::Empty)),
346 Expr::Ref(r) => self.reference(r),
347 Expr::Name { name, sheet } => self.named(name, sheet.as_deref()),
348 Expr::Call(name, args) => self.call(name, args),
349 Expr::Neg(x) => {
350 let v = self.scalar(x)?;
351 Ok(Arg::Scalar(match v.number() {
352 Ok(n) => finite(-n),
353 Err(k) => Value::Error(k),
354 }))
355 }
356 Expr::Pos(x) => self.eval(x),
358 Expr::Percent(x) => {
359 let v = self.scalar(x)?;
360 Ok(Arg::Scalar(match v.number() {
361 Ok(n) => finite(n / 100.0),
362 Err(k) => Value::Error(k),
363 }))
364 }
365 Expr::Binary(op, l, r) if !matches!(**l, Expr::Binary(..)) => {
368 let a = self.scalar(l)?;
369 let b = self.scalar(r)?;
370 Ok(Arg::Scalar(binary(*op, &a, &b)))
371 }
372 Expr::Binary(..) => self.chain(e),
373 }
374 }
375
376 fn chain<'e>(&self, e: &'e Expr) -> Result<Arg<'e>, Reason> {
384 const NEAR: usize = 16;
385 let mut near: [(BinOp, &Expr); NEAR] = [(BinOp::Add, e); NEAR];
386 let mut far: Vec<(BinOp, &Expr)> = Vec::new();
387 let mut links = 0;
388 let mut left = e;
389 while let Expr::Binary(op, l, r) = left {
390 if links < NEAR {
391 near[links] = (*op, r);
392 } else {
393 far.push((*op, r));
394 }
395 links += 1;
396 left = l;
397 }
398 let mut acc = self.scalar(left)?;
399 for i in (0..links).rev() {
400 let (op, r) = if i < NEAR { near[i] } else { far[i - NEAR] };
401 let b = self.scalar(r)?;
402 acc = binary(op, &acc, &b);
403 }
404 Ok(Arg::Scalar(acc))
405 }
406
407 pub fn scalar(&self, e: &Expr) -> Result<Value, Reason> {
410 let arg = self.eval(e)?;
411 self.one(&arg)
412 }
413
414 pub fn one(&self, arg: &Arg<'_>) -> Result<Value, Reason> {
416 match arg {
417 Arg::Scalar(v) => Ok(v.clone()),
418 Arg::Area {
419 areas,
420 written,
421 moved,
422 } => match &areas[..] {
423 [a] if a.is_cell() => self.env.read((a.sheet, a.top, a.left)),
424 _ if *moved == (0, 0) => Err(Reason::Construct(written.to_string())),
425 _ => Err(Reason::Construct(crate::refers::shift_a1_references(
427 written, moved.0, moved.1,
428 ))),
429 },
430 }
431 }
432
433 pub fn truth(&self, e: &Expr) -> Result<Result<bool, ErrorKind>, Reason> {
441 Ok(self.scalar(e)?.truth())
442 }
443
444 pub fn truth_arg(&self, arg: &Arg<'_>) -> Result<Result<bool, ErrorKind>, Reason> {
446 Ok(self.one(arg)?.truth())
447 }
448
449 pub fn each<F>(&self, areas: &[Area], mut f: F) -> Result<(), Reason>
456 where
457 F: FnMut(Value) -> Result<(), Reason>,
458 {
459 let model = self.env.model();
460 for a in areas {
461 if let Some(kept) = self.env.dense(a.sheet) {
462 kept.each(a, &mut f)?;
463 continue;
464 }
465 let Some(sheet) = model.sheets.get(a.sheet) else {
466 continue;
467 };
468 for ((row, col), _) in cells_in(sheet, self.env.extent(a.sheet), a) {
469 let v = self.env.read((a.sheet, row, col))?;
470 if v != Value::Empty {
471 f(v)?;
472 }
473 }
474 }
475 Ok(())
476 }
477
478 pub(super) fn reference<'e>(&self, r: &'e RefExpr) -> Result<Arg<'e>, Reason> {
479 let home = self.env.here().0;
480 let (d_row, d_col) = self.offset.get();
481 match areas_at(self.env.model(), home, r, d_row, d_col) {
482 Ok(areas) => Ok(Arg::Area {
483 areas,
484 written: Cow::Borrowed(&r.written),
485 moved: (d_row, d_col),
486 }),
487 Err(k) => Ok(Arg::Scalar(Value::Error(k))),
488 }
489 }
490
491 fn named(&self, name: &str, sheet: Option<&str>) -> Result<Arg<'static>, Reason> {
495 let model = self.env.model();
496 let home = self.env.here().0;
497 let scope = match sheet {
498 None => None,
499 Some(s) => match model.find_sheet(s) {
500 Some(i) => Some(i),
501 None => return Ok(Arg::Scalar(Value::Error(ErrorKind::Ref))),
502 },
503 };
504 let Some(text) = self.env.name(name, scope, home) else {
505 return Ok(Arg::Scalar(Value::Error(ErrorKind::Name)));
506 };
507 if self.depth.get() >= NAME_DEPTH {
508 return Ok(Arg::Scalar(Value::Error(ErrorKind::Name)));
509 }
510 let parsed = formula::parse(text).map_err(Reason::Construct)?;
511 let offset = self.offset.replace((0, 0));
513 self.depth.set(self.depth.get() + 1);
514 let result = self.eval(&parsed).map(Arg::into_owned);
515 self.depth.set(self.depth.get() - 1);
516 self.offset.set(offset);
517 result
518 }
519
520 fn call<'e>(&self, name: &str, args: &'e [Expr]) -> Result<Arg<'e>, Reason> {
521 if let Some(form) = self.lib.form(name) {
522 return form(self, args);
523 }
524 if let Some(f) = self.lib.strict(name) {
525 return match args {
531 [a] => self.strict_one(f, a),
532 [a, b] => self.strict_two(f, a, b),
533 _ => {
534 let mut values = Vec::with_capacity(args.len());
535 for a in args {
536 values.push(self.eval(a)?);
537 }
538 f(self, &values)
539 }
540 }
541 .map(Arg::Scalar);
542 }
543 Err(Reason::Function(name.to_string()))
544 }
545
546 fn strict_one(&self, f: Strict, a: &Expr) -> Result<Value, Reason> {
548 let x = self.eval(a)?;
549 f(self, std::slice::from_ref(&x))
550 }
551
552 fn strict_two(&self, f: Strict, a: &Expr, b: &Expr) -> Result<Value, Reason> {
554 let pair = [self.eval(a)?, self.eval(b)?];
555 f(self, &pair)
556 }
557}
558
559pub fn finite(v: f64) -> Value {
561 if v == 0.0 {
562 Value::Number(0.0)
564 } else if v.is_finite() {
565 Value::Number(v)
566 } else {
567 Value::Error(ErrorKind::Num)
568 }
569}
570
571pub fn binary(op: BinOp, a: &Value, b: &Value) -> Value {
578 if let Value::Error(k) = a {
579 return Value::Error(*k);
580 }
581 if let Value::Error(k) = b {
582 return Value::Error(*k);
583 }
584 match op {
585 BinOp::Add | BinOp::Sub | BinOp::Mul | BinOp::Div | BinOp::Pow => {
586 let x = match a.number() {
587 Ok(n) => n,
588 Err(k) => return Value::Error(k),
589 };
590 let y = match b.number() {
591 Ok(n) => n,
592 Err(k) => return Value::Error(k),
593 };
594 arithmetic(op, x, y)
595 }
596 BinOp::Concat => match (a.text(), b.text()) {
597 (Ok(s), Ok(t)) => Value::Text(s + &t),
598 (Err(k), _) | (_, Err(k)) => Value::Error(k),
599 },
600 _ => Value::Bool(compares(op, compare(a, b))),
601 }
602}
603
604#[inline]
606pub(crate) fn arithmetic(op: BinOp, x: f64, y: f64) -> Value {
607 match op {
608 BinOp::Add => finite(x + y),
609 BinOp::Sub => finite(x - y),
610 BinOp::Mul => finite(x * y),
611 BinOp::Div => {
612 if y == 0.0 {
613 Value::Error(ErrorKind::Div0)
614 } else {
615 finite(x / y)
616 }
617 }
618 _ => power(x, y),
619 }
620}
621
622#[inline]
624pub(crate) fn compares(op: BinOp, ordering: Ordering) -> bool {
625 match op {
626 BinOp::Eq => ordering == Ordering::Equal,
627 BinOp::Ne => ordering != Ordering::Equal,
628 BinOp::Lt => ordering == Ordering::Less,
629 BinOp::Gt => ordering == Ordering::Greater,
630 BinOp::Le => ordering != Ordering::Greater,
631 _ => ordering != Ordering::Less,
632 }
633}
634
635#[inline]
637pub(crate) fn compare_numbers(x: f64, y: f64) -> Ordering {
638 x.partial_cmp(&y).unwrap_or(Ordering::Equal)
639}
640
641fn power(x: f64, y: f64) -> Value {
644 if x == 0.0 && y == 0.0 {
645 return Value::Error(ErrorKind::Num);
646 }
647 if x == 0.0 && y < 0.0 {
648 return Value::Error(ErrorKind::Div0);
649 }
650 finite(x.powf(y))
651}
652
653pub fn compare(a: &Value, b: &Value) -> Ordering {
657 use Value::*;
658 match (a, b) {
659 (Empty, Empty) => Ordering::Equal,
660 (Empty, Number(y)) => 0.0f64.partial_cmp(y).unwrap_or(Ordering::Equal),
661 (Number(x), Empty) => x.partial_cmp(&0.0).unwrap_or(Ordering::Equal),
662 (Empty, Text(t)) => {
663 if t.is_empty() {
664 Ordering::Equal
665 } else {
666 Ordering::Less
667 }
668 }
669 (Text(t), Empty) => {
670 if t.is_empty() {
671 Ordering::Equal
672 } else {
673 Ordering::Greater
674 }
675 }
676 (Empty, Bool(y)) => false.cmp(y),
677 (Bool(x), Empty) => x.cmp(&false),
678 (Number(x), Number(y)) => compare_numbers(*x, *y),
679 (Text(x), Text(y)) => fold(x).cmp(&fold(y)),
680 (Bool(x), Bool(y)) => x.cmp(y),
681 _ => rank(a).cmp(&rank(b)),
682 }
683}
684
685fn rank(v: &Value) -> u8 {
686 match v {
687 Value::Number(_) | Value::Empty => 0,
688 Value::Text(_) => 1,
689 Value::Bool(_) => 2,
690 Value::Error(_) => 3,
691 }
692}
693
694#[cfg(test)]
695mod tests {
696 use super::*;
697
698 #[test]
699 fn operators_coerce_as_excel_does() {
700 let n = |v: f64| Value::Number(v);
701 let t = |s: &str| Value::Text(s.to_string());
702 assert_eq!(binary(BinOp::Add, &t("5"), &n(1.0)), n(6.0));
703 assert_eq!(
704 binary(BinOp::Add, &t("x"), &n(1.0)),
705 Value::Error(ErrorKind::Value)
706 );
707 assert_eq!(binary(BinOp::Mul, &Value::Bool(true), &n(3.0)), n(3.0));
708 assert_eq!(binary(BinOp::Add, &Value::Empty, &n(1.0)), n(1.0));
709 assert_eq!(
710 binary(BinOp::Div, &n(1.0), &n(0.0)),
711 Value::Error(ErrorKind::Div0)
712 );
713 assert_eq!(
714 binary(BinOp::Div, &n(1.0), &Value::Empty),
715 Value::Error(ErrorKind::Div0)
716 );
717 assert_eq!(
718 binary(BinOp::Pow, &n(0.0), &n(0.0)),
719 Value::Error(ErrorKind::Num)
720 );
721 assert_eq!(
722 binary(BinOp::Pow, &n(0.0), &n(-1.0)),
723 Value::Error(ErrorKind::Div0)
724 );
725 assert_eq!(
726 binary(BinOp::Pow, &n(-8.0), &n(1.0 / 3.0)),
727 Value::Error(ErrorKind::Num)
728 );
729 assert_eq!(binary(BinOp::Pow, &n(2.0), &n(10.0)), n(1024.0));
730 assert_eq!(
731 binary(BinOp::Mul, &n(1e308), &n(10.0)),
732 Value::Error(ErrorKind::Num)
733 );
734 assert_eq!(binary(BinOp::Concat, &n(1.0), &n(2.0)), t("12"));
735 assert_eq!(
736 binary(BinOp::Concat, &Value::Bool(true), &Value::Empty),
737 t("TRUE")
738 );
739 assert_eq!(binary(BinOp::Concat, &n(0.1 + 0.2), &t("")), t("0.3"));
740 assert_eq!(
742 binary(
743 BinOp::Add,
744 &Value::Error(ErrorKind::NA),
745 &Value::Error(ErrorKind::Div0)
746 ),
747 Value::Error(ErrorKind::NA)
748 );
749 }
750
751 #[test]
752 fn comparisons_follow_excel_s_order_of_kinds() {
753 let n = |v: f64| Value::Number(v);
754 let t = |s: &str| Value::Text(s.to_string());
755 let yes = Value::Bool(true);
756 assert_eq!(binary(BinOp::Eq, &t("ABC"), &t("abc")), yes);
757 assert_eq!(binary(BinOp::Lt, &n(1e9), &t("")), yes);
758 assert_eq!(binary(BinOp::Gt, &Value::Bool(false), &t("zzz")), yes);
759 assert_eq!(binary(BinOp::Eq, &Value::Empty, &n(0.0)), yes);
760 assert_eq!(binary(BinOp::Eq, &Value::Empty, &t("")), yes);
761 assert_eq!(binary(BinOp::Eq, &Value::Empty, &Value::Bool(false)), yes);
762 assert_eq!(binary(BinOp::Ne, &n(1.0), &t("1")), yes);
763 assert_eq!(binary(BinOp::Le, &n(2.0), &n(2.0)), yes);
764 assert_eq!(binary(BinOp::Ge, &n(1.0), &n(2.0)), Value::Bool(false));
765 }
766
767 #[test]
768 fn the_library_is_keyed_without_case_and_a_name_holds_one_kind() {
769 let mut lib = Library::empty();
770 fn one(_: &Ctx<'_>, _: &[Arg]) -> Result<Value, Reason> {
771 Ok(Value::Number(1.0))
772 }
773 fn two<'e>(_: &Ctx<'_>, _: &'e [Expr]) -> Result<Arg<'e>, Reason> {
774 Ok(Arg::Scalar(Value::Number(2.0)))
775 }
776 lib.register("one", one);
777 lib.register_form("Two", two);
778 assert!(lib.has("ONE") && lib.has("two"));
779 assert_eq!(lib.names(), vec!["ONE", "TWO"]);
780 assert!(lib.strict("one").is_some() && lib.form("one").is_none());
781 lib.register_form("one", two);
782 assert!(lib.strict("one").is_none() && lib.form("one").is_some());
783 assert_eq!(lib.len(), 2);
784 }
785
786 #[test]
787 fn a_name_is_upper_cased_only_when_that_would_change_it() {
788 fn one(_: &Ctx<'_>, _: &[Arg]) -> Result<Value, Reason> {
792 Ok(Value::Number(1.0))
793 }
794 assert!(matches!(key("SUM"), Cow::Borrowed("SUM")));
795 assert!(matches!(key("ÄRGER"), Cow::Borrowed("ÄRGER")));
796 assert_eq!(key("Sum"), "SUM");
797 assert_eq!(key("ärger"), "äRGER");
798 let mut lib = Library::empty();
799 lib.register("Ärger", one);
800 lib.register("sum", one);
801 assert_eq!(lib.names(), vec!["SUM", "ÄRGER"]);
802 for (name, found) in [
803 ("SUM", true),
804 ("Sum", true),
805 ("sum", true),
806 ("ÄRGER", true),
807 ("Ärger", true),
808 ("ärger", false),
809 ("äRGER", false),
810 ] {
811 assert_eq!(lib.strict(name).is_some(), found, "{name}");
812 assert_eq!(lib.has(name), found, "{name}");
813 assert!(lib.form(name).is_none(), "{name}");
814 }
815 }
816}