1use crate::engine::lookup_index_cache::{LookupAxis, LookupIndex};
2use crate::engine::range_view::RangeView;
3use crate::engine::row_visibility::VisibilityMaskMode;
4pub use crate::function::Function;
5use crate::interpreter::Interpreter;
6use crate::reference::CellRef;
7use formualizer_common::{
8 LiteralValue,
9 error::{ExcelError, ExcelErrorKind},
10};
11use std::any::Any;
12use std::borrow::Cow;
13use std::fmt::Debug;
14use std::sync::Arc;
15
16use formualizer_parse::parser::{ASTNode, ASTNodeType, ReferenceType, TableSpecifier};
17
18#[derive(Clone, Debug, Eq, PartialEq)]
19pub struct ReferenceInfo {
20 pub first_sheet_index: Option<usize>,
22 pub sheet_count: Option<usize>,
24 pub first_cell: Option<CellRef>,
26}
27
28pub trait Range: Debug + Send + Sync {
31 fn get(&self, row: usize, col: usize) -> Result<LiteralValue, ExcelError>;
32 fn dimensions(&self) -> (usize, usize);
33
34 fn is_sparse(&self) -> bool {
35 false
36 }
37
38 fn is_infinite(&self) -> bool {
40 false
41 }
42
43 fn materialise(&self) -> Cow<'_, [Vec<LiteralValue>]> {
44 Cow::Owned(
45 (0..self.dimensions().0)
46 .map(|r| {
47 (0..self.dimensions().1)
48 .map(|c| self.get(r, c).unwrap_or(LiteralValue::Empty))
49 .collect()
50 })
51 .collect(),
52 )
53 }
54
55 fn iter_cells<'a>(&'a self) -> Box<dyn Iterator<Item = LiteralValue> + 'a> {
56 let (rows, cols) = self.dimensions();
57 Box::new((0..rows).flat_map(move |r| (0..cols).map(move |c| self.get(r, c).unwrap())))
58 }
59 fn iter_rows<'a>(&'a self) -> Box<dyn Iterator<Item = Vec<LiteralValue>> + 'a> {
60 let (rows, cols) = self.dimensions();
61 Box::new((0..rows).map(move |r| (0..cols).map(|c| self.get(r, c).unwrap()).collect()))
62 }
63
64 fn as_any(&self) -> &dyn Any;
66}
67
68impl Range for Box<dyn Range> {
70 fn get(&self, r: usize, c: usize) -> Result<LiteralValue, ExcelError> {
71 (**self).get(r, c)
72 }
73 fn dimensions(&self) -> (usize, usize) {
74 (**self).dimensions()
75 }
76 fn is_sparse(&self) -> bool {
77 (**self).is_sparse()
78 }
79 fn materialise(&self) -> Cow<'_, [Vec<LiteralValue>]> {
80 (**self).materialise()
81 }
82 fn iter_cells<'a>(&'a self) -> Box<dyn Iterator<Item = LiteralValue> + 'a> {
83 (**self).iter_cells()
84 }
85 fn iter_rows<'a>(&'a self) -> Box<dyn Iterator<Item = Vec<LiteralValue>> + 'a> {
86 (**self).iter_rows()
87 }
88 fn as_any(&self) -> &dyn Any {
89 (**self).as_any()
90 }
91}
92
93pub type CowValue<'a> = Cow<'a, LiteralValue>;
96
97pub trait CustomCallable: Send + Sync {
98 fn arity(&self) -> usize;
99
100 fn invoke<'ctx>(
101 &self,
102 interp: &Interpreter<'ctx>,
103 args: &[LiteralValue],
104 ) -> Result<CalcValue<'ctx>, ExcelError>;
105
106 fn invoke_with_references<'ctx>(
120 &self,
121 interp: &Interpreter<'ctx>,
122 args: &[LiteralValue],
123 references: &[Option<ReferenceType>],
124 ) -> Result<CalcValue<'ctx>, ExcelError> {
125 let _ = references;
126 self.invoke(interp, args)
127 }
128}
129
130#[derive(Clone)]
131pub enum CalcValue<'a> {
132 Scalar(LiteralValue),
133 AnnotatedScalar(LiteralValue, crate::format::FormatId),
135 Range(RangeView<'a>),
136 Callable(Arc<dyn CustomCallable>),
137}
138
139#[derive(Clone)]
145pub(crate) enum ResolvedArgument<'a> {
146 Range(RangeView<'a>),
147 ReferenceError(ExcelError),
148 Value(CalcValue<'a>),
149}
150
151impl std::fmt::Debug for ResolvedArgument<'_> {
152 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
153 match self {
154 Self::Range(view) => f.debug_tuple("Range").field(view).finish(),
155 Self::ReferenceError(error) => f.debug_tuple("ReferenceError").field(error).finish(),
156 Self::Value(value) => f.debug_tuple("Value").field(value).finish(),
157 }
158 }
159}
160
161impl<'a> std::fmt::Debug for CalcValue<'a> {
162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
163 match self {
164 CalcValue::Scalar(v) => f.debug_tuple("Scalar").field(v).finish(),
165 CalcValue::AnnotatedScalar(v, format) => f
166 .debug_tuple("AnnotatedScalar")
167 .field(v)
168 .field(format)
169 .finish(),
170 CalcValue::Range(rv) => {
171 let (r, c) = rv.dims();
172 f.debug_tuple("Range").field(&(r, c)).finish()
173 }
174 CalcValue::Callable(_) => f.write_str("Callable(<opaque>)"),
175 }
176 }
177}
178
179#[cfg(test)]
182thread_local! {
183 pub(crate) static RANGE_MATERIALIZED_CELLS: std::cell::Cell<usize> = const { std::cell::Cell::new(0) };
184}
185
186impl<'a> CalcValue<'a> {
187 pub fn into_literal(self) -> LiteralValue {
188 match self {
189 CalcValue::Scalar(s) | CalcValue::AnnotatedScalar(s, _) => s,
190 CalcValue::Range(rv) => {
191 let (rows, cols) = rv.dims();
192 #[cfg(test)]
193 RANGE_MATERIALIZED_CELLS.with(|count| count.set(count.get() + rows * cols));
194 if rows == 1 && cols == 1 {
195 rv.get_cell(0, 0)
196 } else {
197 let mut data = Vec::with_capacity(rows);
198 for row_idx in 0..rows {
199 let mut row = Vec::with_capacity(cols);
200 for col_idx in 0..cols {
201 row.push(rv.get_cell(row_idx, col_idx));
202 }
203 data.push(row);
204 }
205 LiteralValue::Array(data)
206 }
207 }
208 CalcValue::Callable(_) => LiteralValue::Error(
209 ExcelError::new(ExcelErrorKind::Calc).with_message("LAMBDA value must be invoked"),
210 ),
211 }
212 }
213
214 pub fn as_scalar(&self) -> Option<&LiteralValue> {
215 match self {
216 CalcValue::Scalar(s) | CalcValue::AnnotatedScalar(s, _) => Some(s),
217 _ => None,
218 }
219 }
220
221 pub fn format_id(&self) -> Option<crate::format::FormatId> {
222 match self {
223 CalcValue::AnnotatedScalar(_, format) => Some(*format),
224 _ => None,
225 }
226 }
227
228 pub fn with_format(self, format: Option<crate::format::FormatId>) -> Self {
229 let format = format.filter(|id| *id != crate::format::FormatId::GENERAL);
230 match (self, format) {
231 (CalcValue::Scalar(value) | CalcValue::AnnotatedScalar(value, _), Some(id)) => {
232 CalcValue::AnnotatedScalar(value, id)
233 }
234 (CalcValue::AnnotatedScalar(value, _), None) => CalcValue::Scalar(value),
235 (other, _) => other,
236 }
237 }
238
239 pub fn into_scalar_parts(self) -> (LiteralValue, Option<crate::format::FormatId>) {
240 match self {
241 CalcValue::Scalar(value) => (value, None),
242 CalcValue::AnnotatedScalar(value, format) => (value, Some(format)),
243 other => (other.into_literal(), None),
244 }
245 }
246
247 pub fn as_range(&self) -> Option<&RangeView<'a>> {
248 match self {
249 CalcValue::Range(r) => Some(r),
250 _ => None,
251 }
252 }
253
254 pub fn as_callable(&self) -> Option<&Arc<dyn CustomCallable>> {
255 match self {
256 CalcValue::Callable(c) => Some(c),
257 _ => None,
258 }
259 }
260
261 pub fn into_owned(self) -> LiteralValue {
262 self.into_literal()
263 }
264}
265
266impl From<CalcValue<'_>> for LiteralValue {
267 fn from(val: CalcValue<'_>) -> Self {
268 val.into_literal()
269 }
270}
271
272impl<'a> PartialEq<LiteralValue> for CalcValue<'a> {
273 fn eq(&self, other: &LiteralValue) -> bool {
274 match self {
275 CalcValue::Scalar(s) | CalcValue::AnnotatedScalar(s, _) => s == other,
276 CalcValue::Range(rv) => match other {
277 LiteralValue::Array(arr) => {
278 let (rows, cols) = rv.dims();
279 if arr.len() != rows {
280 return false;
281 }
282 for (r, row) in arr.iter().enumerate() {
283 if row.len() != cols {
284 return false;
285 }
286 for (c, cell) in row.iter().enumerate() {
287 if &rv.get_cell(r, c) != cell {
288 return false;
289 }
290 }
291 }
292 true
293 }
294 _ => {
295 let (rows, cols) = rv.dims();
296 rows == 1 && cols == 1 && &rv.get_cell(0, 0) == other
297 }
298 },
299 CalcValue::Callable(_) => false,
300 }
301 }
302}
303
304impl<'a> PartialEq<CalcValue<'a>> for LiteralValue {
305 fn eq(&self, other: &CalcValue<'a>) -> bool {
306 other == self
307 }
308}
309
310pub enum EvaluatedArg<'a> {
311 LiteralValue(CowValue<'a>),
312 Range(Box<dyn Range>),
313}
314
315enum ArgumentExpr<'a> {
316 Ast(&'a ASTNode),
317 Arena {
318 id: crate::engine::arena::AstNodeId,
319 data_store: &'a crate::engine::arena::DataStore,
320 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
321 },
322}
323
324pub struct ArgumentHandle<'a, 'b> {
325 expr: ArgumentExpr<'a>,
326 interp: &'a Interpreter<'b>,
327 cached_ast: std::cell::OnceCell<ASTNode>,
328 cached_ref: std::cell::OnceCell<ReferenceType>,
329 cached_reference_or_value:
330 std::cell::OnceCell<Result<crate::function::FunctionResolution<'b>, ExcelError>>,
331 cached_resolved: std::cell::OnceCell<Result<ResolvedArgument<'b>, ExcelError>>,
332 cached_value: std::cell::OnceCell<Result<crate::traits::CalcValue<'b>, ExcelError>>,
341}
342
343impl<'a, 'b> ArgumentHandle<'a, 'b> {
344 pub(crate) fn new(node: &'a ASTNode, interp: &'a Interpreter<'b>) -> Self {
345 Self {
346 expr: ArgumentExpr::Ast(node),
347 interp,
348 cached_ast: std::cell::OnceCell::new(),
349 cached_ref: std::cell::OnceCell::new(),
350 cached_reference_or_value: std::cell::OnceCell::new(),
351 cached_resolved: std::cell::OnceCell::new(),
352 cached_value: std::cell::OnceCell::new(),
353 }
354 }
355
356 pub(crate) fn new_arena(
357 id: crate::engine::arena::AstNodeId,
358 interp: &'a Interpreter<'b>,
359 data_store: &'a crate::engine::arena::DataStore,
360 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
361 ) -> Self {
362 Self {
363 expr: ArgumentExpr::Arena {
364 id,
365 data_store,
366 sheet_registry,
367 },
368 interp,
369 cached_ast: std::cell::OnceCell::new(),
370 cached_ref: std::cell::OnceCell::new(),
371 cached_reference_or_value: std::cell::OnceCell::new(),
372 cached_resolved: std::cell::OnceCell::new(),
373 cached_value: std::cell::OnceCell::new(),
374 }
375 }
376
377 pub(crate) fn date_system(&self) -> crate::engine::DateSystem {
383 self.interp.context.date_system()
384 }
385
386 pub fn is_omitted(&self) -> bool {
390 match &self.expr {
391 ArgumentExpr::Ast(node) => matches!(node.node_type, ASTNodeType::Omitted),
392 ArgumentExpr::Arena { id, data_store, .. } => matches!(
393 data_store.get_node(*id),
394 Some(crate::engine::arena::AstNodeData::Omitted)
395 ),
396 }
397 }
398
399 pub(crate) fn bare_reference(&self) -> Option<ReferenceType> {
412 let is_reference = match &self.expr {
413 ArgumentExpr::Ast(node) => matches!(node.node_type, ASTNodeType::Reference { .. }),
414 ArgumentExpr::Arena { id, data_store, .. } => matches!(
415 data_store.get_node(*id),
416 Some(crate::engine::arena::AstNodeData::Reference { .. })
417 ),
418 };
419 if !is_reference {
420 return None;
421 }
422 self.as_reference_or_eval().ok()
423 }
424
425 pub(crate) fn has_reference_semantics(&self) -> bool {
431 self.reference_attempt().is_some()
432 }
433
434 pub(crate) fn may_return_reference(&self) -> bool {
439 match &self.expr {
440 ArgumentExpr::Ast(node) => match &node.node_type {
441 ASTNodeType::Reference { reference, .. } => match reference {
442 ReferenceType::NamedRange(name)
444 if self.interp.resolve_local_name(name).is_some() =>
445 {
446 self.interp.resolve_local_bound_reference(name).is_some()
447 }
448 _ => true,
449 },
450 ASTNodeType::BinaryOp { op, .. } => op == ":",
451 ASTNodeType::Function { name, .. } => self
452 .interp
453 .context
454 .function_capabilities("", name)
455 .is_some_and(|caps| caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)),
456 _ => false,
457 },
458 ArgumentExpr::Arena { id, data_store, .. } => match data_store.get_node(*id) {
459 Some(crate::engine::arena::AstNodeData::Reference { ref_type, .. }) => {
460 match ref_type {
461 crate::engine::arena::CompactRefType::NamedRange(name_id)
463 if self
464 .interp
465 .resolve_local_name(data_store.resolve_ast_string(*name_id))
466 .is_some() =>
467 {
468 self.interp
469 .resolve_local_bound_reference(
470 data_store.resolve_ast_string(*name_id),
471 )
472 .is_some()
473 }
474 _ => true,
475 }
476 }
477 Some(crate::engine::arena::AstNodeData::BinaryOp { op_id, .. }) => {
478 data_store.resolve_ast_string(*op_id) == ":"
479 }
480 Some(crate::engine::arena::AstNodeData::Function { name_id, .. }) => self
481 .interp
482 .context
483 .function_capabilities("", data_store.resolve_ast_string(*name_id))
484 .is_some_and(|caps| caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)),
485 _ => false,
486 },
487 }
488 }
489
490 pub fn value(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
491 self.cached_value
492 .get_or_init(|| self.compute_value())
493 .clone()
494 }
495
496 pub(crate) fn value_for_text(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
502 if self.is_omitted() {
503 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(
504 String::new(),
505 )))
506 } else {
507 self.value()
508 }
509 }
510
511 pub(crate) fn resolve_once_for_text(&self) -> Result<ResolvedArgument<'b>, ExcelError> {
512 if self.is_omitted() {
513 Ok(ResolvedArgument::Value(crate::traits::CalcValue::Scalar(
514 LiteralValue::Text(String::new()),
515 )))
516 } else {
517 self.resolve_once()
518 }
519 }
520
521 fn compute_value(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
522 match &self.expr {
523 ArgumentExpr::Ast(node) => match &node.node_type {
524 ASTNodeType::Literal(v) => Ok(crate::traits::CalcValue::Scalar(v.clone())),
525 ASTNodeType::Omitted => {
528 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
529 }
530 _ => self.interp.evaluate_ast(node),
531 },
532 ArgumentExpr::Arena {
533 id,
534 data_store,
535 sheet_registry,
536 } => {
537 if matches!(
538 data_store.get_node(*id),
539 Some(crate::engine::arena::AstNodeData::Omitted)
540 ) {
541 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
542 } else {
543 self.interp
544 .evaluate_arena_ast(*id, data_store, sheet_registry)
545 }
546 }
547 }
548 }
549
550 pub fn value_with_env(
551 &self,
552 env: crate::interpreter::LocalEnv,
553 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
554 let scoped = self.interp.with_local_env(env);
555 match &self.expr {
556 ArgumentExpr::Ast(node) => match &node.node_type {
557 ASTNodeType::Literal(v) => Ok(crate::traits::CalcValue::Scalar(v.clone())),
558 ASTNodeType::Omitted => {
559 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
560 }
561 _ => scoped.evaluate_ast(node),
562 },
563 ArgumentExpr::Arena {
564 id,
565 data_store,
566 sheet_registry,
567 } => {
568 if matches!(
569 data_store.get_node(*id),
570 Some(crate::engine::arena::AstNodeData::Omitted)
571 ) {
572 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
573 } else {
574 scoped.evaluate_arena_ast(*id, data_store, sheet_registry)
575 }
576 }
577 }
578 }
579
580 pub fn current_env(&self) -> crate::interpreter::LocalEnv {
581 self.interp.local_env().clone()
582 }
583
584 pub(crate) fn bound_reference_in_env(
591 &self,
592 env: &crate::interpreter::LocalEnv,
593 ) -> Option<ReferenceType> {
594 match &self.expr {
595 ArgumentExpr::Ast(node) => match &node.node_type {
596 ASTNodeType::Reference { reference, .. } => {
597 if let ReferenceType::NamedRange(name) = reference
598 && let Some(binding) = env.lookup(name)
599 {
600 return match binding {
602 crate::interpreter::LocalBinding::ValueWithReference {
603 reference,
604 ..
605 } => Some(reference),
606 _ => None,
607 };
608 }
609 self.interp.reference_for_current_offset(reference).ok()
610 }
611 ASTNodeType::BinaryOp { op, .. } if op == ":" => self
612 .interp
613 .with_local_env(env.clone())
614 .evaluate_ast_as_reference(node)
615 .ok(),
616 _ => None,
617 },
618 ArgumentExpr::Arena {
619 id,
620 data_store,
621 sheet_registry,
622 } => match data_store.get_node(*id) {
623 Some(crate::engine::arena::AstNodeData::Reference { ref_type, .. }) => {
624 if let crate::engine::arena::CompactRefType::NamedRange(name_id) = ref_type
625 && let Some(binding) = env.lookup(data_store.resolve_ast_string(*name_id))
626 {
627 return match binding {
628 crate::interpreter::LocalBinding::ValueWithReference {
629 reference,
630 ..
631 } => Some(reference),
632 _ => None,
633 };
634 }
635 let reference =
636 data_store.reconstruct_reference_type_for_eval(ref_type, sheet_registry);
637 self.interp.reference_for_current_offset(&reference).ok()
638 }
639 Some(crate::engine::arena::AstNodeData::BinaryOp { op_id, .. })
640 if data_store.resolve_ast_string(*op_id) == ":" =>
641 {
642 self.interp
643 .with_local_env(env.clone())
644 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry)
645 .ok()
646 }
647 _ => None,
648 },
649 }
650 }
651
652 pub fn inline_array_literal(&self) -> Result<Option<Vec<Vec<LiteralValue>>>, ExcelError> {
653 match &self.expr {
654 ArgumentExpr::Ast(node) => match &node.node_type {
655 ASTNodeType::Literal(LiteralValue::Array(arr)) => Ok(Some(arr.clone())),
656 _ => Ok(None),
657 },
658 ArgumentExpr::Arena {
659 id,
660 data_store,
661 sheet_registry,
662 } => {
663 let node = data_store.get_node(*id).ok_or_else(|| {
664 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
665 })?;
666 match node {
667 crate::engine::arena::AstNodeData::Literal(vref) => {
668 match data_store.retrieve_value(*vref) {
669 LiteralValue::Array(arr) => Ok(Some(arr)),
670 _ => Ok(None),
671 }
672 }
673 _ => {
674 let _ = sheet_registry;
677 Ok(None)
678 }
679 }
680 }
681 }
682 }
683
684 fn local_named_reference(&self, name: &str) -> Option<Result<ReferenceType, ExcelError>> {
703 self.interp.resolve_local_name(name)?;
705 Some(
706 self.interp
707 .resolve_local_bound_reference(name)
708 .ok_or_else(|| {
709 ExcelError::new(ExcelErrorKind::Value)
710 .with_message("LET/LAMBDA local is not a reference")
711 }),
712 )
713 }
714
715 fn reference_for_eval(&self) -> Result<ReferenceType, ExcelError> {
716 match &self.expr {
717 ArgumentExpr::Ast(node) => match &node.node_type {
718 ASTNodeType::Reference { reference, .. } => {
719 if let ReferenceType::NamedRange(name) = reference
722 && let Some(local) = self.local_named_reference(name)
723 {
724 return local;
725 }
726 self.interp.reference_for_current_offset(reference)
727 }
728 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
729 self.interp.evaluate_ast_as_reference(node)
730 }
731 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
732 .with_message("Expected a reference (by-ref argument)")),
733 },
734 ArgumentExpr::Arena {
735 id,
736 data_store,
737 sheet_registry,
738 } => {
739 let node = data_store.get_node(*id).ok_or_else(|| {
740 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
741 })?;
742 match node {
743 crate::engine::arena::AstNodeData::Reference { ref_type, .. } => {
744 if let crate::engine::arena::CompactRefType::NamedRange(name_id) = ref_type
746 && let Some(local) =
747 self.local_named_reference(data_store.resolve_ast_string(*name_id))
748 {
749 return local;
750 }
751 let reference = data_store
752 .reconstruct_reference_type_for_eval(ref_type, sheet_registry);
753 self.interp.reference_for_current_offset(&reference)
754 }
755 crate::engine::arena::AstNodeData::Function { .. }
756 | crate::engine::arena::AstNodeData::BinaryOp { .. } => self
757 .interp
758 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry),
759 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
760 .with_message("Expected a reference (by-ref argument)")),
761 }
762 }
763 }
764 }
765
766 fn function_resolution_attempt(
767 &self,
768 ) -> Option<Result<crate::function::FunctionResolution<'b>, ExcelError>> {
769 match &self.expr {
770 ArgumentExpr::Ast(node) => {
771 let ASTNodeType::Function { name, args } = &node.node_type else {
772 return None;
773 };
774 if !self
775 .interp
776 .context
777 .function_capabilities("", name)
778 .is_some_and(|caps| caps.contains(crate::function::FnCaps::RETURNS_REFERENCE))
779 {
780 return None;
781 }
782 let fun = match self.interp.context.get_function("", name) {
783 Some(fun) => fun,
784 None => {
785 return Some(Err(ExcelError::new(ExcelErrorKind::Name)
786 .with_message(format!("Unknown function: {name}"))));
787 }
788 };
789 let handles: Vec<_> = args
790 .iter()
791 .map(|arg| ArgumentHandle::new(arg, self.interp))
792 .collect();
793 let ctx = DefaultFunctionContext::new_with_sheet(
794 self.interp.context,
795 None,
796 self.interp.current_sheet(),
797 );
798 Some(fun.resolve_reference_or_value(&handles, &ctx, &|| self.value()))
799 }
800 ArgumentExpr::Arena {
801 id,
802 data_store,
803 sheet_registry,
804 } => {
805 let node = match data_store.get_node(*id) {
806 Some(node) => node,
807 None => {
808 return Some(Err(
809 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
810 ));
811 }
812 };
813 let crate::engine::arena::AstNodeData::Function { name_id, .. } = node else {
814 return None;
815 };
816 let name = data_store.resolve_ast_string(*name_id);
817 if !self
818 .interp
819 .context
820 .function_capabilities("", name)
821 .is_some_and(|caps| caps.contains(crate::function::FnCaps::RETURNS_REFERENCE))
822 {
823 return None;
824 }
825 let fun = match self.interp.context.get_function("", name) {
826 Some(fun) => fun,
827 None => {
828 return Some(Err(ExcelError::new(ExcelErrorKind::Name)
829 .with_message(format!("Unknown function: {name}"))));
830 }
831 };
832 let args = match data_store.get_args(*id) {
833 Some(args) => args,
834 None => {
835 return Some(Err(ExcelError::new(ExcelErrorKind::Value)
836 .with_message("Missing function args")));
837 }
838 };
839 let handles: Vec<_> = args
840 .iter()
841 .copied()
842 .map(|arg_id| {
843 ArgumentHandle::new_arena(arg_id, self.interp, data_store, sheet_registry)
844 })
845 .collect();
846 let ctx = DefaultFunctionContext::new_with_sheet(
847 self.interp.context,
848 None,
849 self.interp.current_sheet(),
850 );
851 Some(fun.resolve_reference_or_value(&handles, &ctx, &|| self.value()))
852 }
853 }
854 }
855
856 fn reference_attempt(&self) -> Option<Result<ReferenceType, ExcelError>> {
857 match &self.expr {
858 ArgumentExpr::Ast(node) => match &node.node_type {
859 ASTNodeType::Reference { reference, .. } => {
860 if let ReferenceType::NamedRange(name) = reference
865 && self.interp.resolve_local_name(name).is_some()
866 {
867 return self.interp.resolve_local_bound_reference(name).map(Ok);
868 }
869 Some(self.interp.reference_for_current_offset(reference))
870 }
871 ASTNodeType::BinaryOp { op, .. } if op == ":" => {
872 Some(self.interp.evaluate_ast_as_reference(node))
873 }
874 ASTNodeType::Function { name, .. }
875 if self
876 .interp
877 .context
878 .function_capabilities("", name)
879 .is_some_and(|caps| {
880 caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)
881 }) =>
882 {
883 self.interp.try_evaluate_ast_as_reference(node)
884 }
885 _ => None,
886 },
887 ArgumentExpr::Arena {
888 id,
889 data_store,
890 sheet_registry,
891 } => {
892 let node = match data_store.get_node(*id) {
893 Some(node) => node,
894 None => {
895 return Some(Err(
896 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
897 ));
898 }
899 };
900 match node {
901 crate::engine::arena::AstNodeData::Reference { ref_type, .. } => {
902 if let crate::engine::arena::CompactRefType::NamedRange(name_id) = ref_type
904 {
905 let name = data_store.resolve_ast_string(*name_id);
906 if self.interp.resolve_local_name(name).is_some() {
907 return self.interp.resolve_local_bound_reference(name).map(Ok);
908 }
909 }
910 let reference = data_store
911 .reconstruct_reference_type_for_eval(ref_type, sheet_registry);
912 Some(self.interp.reference_for_current_offset(&reference))
913 }
914 crate::engine::arena::AstNodeData::BinaryOp { op_id, .. }
915 if data_store.resolve_ast_string(*op_id) == ":" =>
916 {
917 Some(self.interp.evaluate_arena_ast_as_reference(
918 *id,
919 data_store,
920 sheet_registry,
921 ))
922 }
923 crate::engine::arena::AstNodeData::Function { name_id, .. } => {
924 let name = data_store.resolve_ast_string(*name_id);
925 if self
926 .interp
927 .context
928 .function_capabilities("", name)
929 .is_some_and(|caps| {
930 caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)
931 })
932 {
933 self.interp.try_evaluate_arena_ast_as_reference(
934 *id,
935 data_store,
936 sheet_registry,
937 )
938 } else {
939 None
940 }
941 }
942 _ => None,
943 }
944 }
945 }
946 }
947
948 pub(crate) fn resolve_reference_or_value(
949 &self,
950 ) -> Result<crate::function::FunctionResolution<'b>, ExcelError> {
951 let resolved = self
952 .cached_reference_or_value
953 .get_or_init(|| self.compute_reference_or_value())
954 .clone();
955 if let Ok(crate::function::FunctionResolution::Value(value)) = &resolved {
956 let _ = self.cached_value.set(Ok(value.clone()));
957 }
958 resolved
959 }
960
961 fn compute_reference_or_value(
962 &self,
963 ) -> Result<crate::function::FunctionResolution<'b>, ExcelError> {
964 if let Some(result) = self.function_resolution_attempt() {
965 return result;
966 }
967 if let Some(reference) = self.reference_attempt() {
968 return Ok(match reference {
969 Ok(reference) => crate::function::FunctionResolution::Reference(reference),
970 Err(error) => crate::function::FunctionResolution::ReferenceError(error),
971 });
972 }
973 self.value().map(crate::function::FunctionResolution::Value)
974 }
975
976 pub(crate) fn resolve_once(&self) -> Result<ResolvedArgument<'b>, ExcelError> {
982 self.cached_resolved
983 .get_or_init(|| self.compute_resolved_argument())
984 .clone()
985 }
986
987 pub(crate) fn with_context_cancel_token(&self, view: RangeView<'b>) -> RangeView<'b> {
988 match self.interp.context.cancellation_token() {
989 Some(token) => view.with_cancel_token(Some(token)),
990 None => view,
991 }
992 }
993
994 fn compute_resolved_argument(&self) -> Result<ResolvedArgument<'b>, ExcelError> {
995 let value = match self.resolve_reference_or_value()? {
996 crate::function::FunctionResolution::Reference(reference) => {
997 return match self
998 .interp
999 .context
1000 .resolve_range_view(&reference, self.interp.current_sheet())
1001 {
1002 Ok(view) => Ok(ResolvedArgument::Range(
1003 self.with_context_cancel_token(view),
1004 )),
1005 Err(error) if error.kind == ExcelErrorKind::Cancelled => Err(error),
1006 Err(error) => Ok(ResolvedArgument::ReferenceError(error)),
1007 };
1008 }
1009 crate::function::FunctionResolution::ReferenceError(error)
1010 if error.kind == ExcelErrorKind::Cancelled =>
1011 {
1012 return Err(error);
1013 }
1014 crate::function::FunctionResolution::ReferenceError(error) => {
1015 return Ok(ResolvedArgument::ReferenceError(error));
1016 }
1017 crate::function::FunctionResolution::Value(value) => value,
1018 };
1019
1020 match value {
1021 CalcValue::Range(view) => Ok(ResolvedArgument::Range(
1022 self.with_context_cancel_token(view),
1023 )),
1024 CalcValue::Scalar(LiteralValue::Array(rows)) => {
1025 let view = RangeView::try_from_owned_rows(
1026 rows,
1027 self.interp.context.date_system(),
1028 self.interp.context.cancellation_token(),
1029 )?;
1030 Ok(ResolvedArgument::Range(view))
1031 }
1032 other => Ok(ResolvedArgument::Value(other)),
1033 }
1034 }
1035
1036 pub fn range(&self) -> Result<Box<dyn Range>, ExcelError> {
1037 match &self.expr {
1038 ArgumentExpr::Ast(node) => match &node.node_type {
1039 ASTNodeType::Reference { reference, .. } => {
1040 let reference = self.interp.reference_for_current_offset(reference)?;
1042 let view = self
1043 .interp
1044 .context
1045 .resolve_range_view(&reference, self.interp.current_sheet())?;
1046 let (rows, cols) = view.dims();
1047 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
1048 view.for_each_row(&mut |row| {
1049 let row_data: Vec<LiteralValue> = (0..cols)
1050 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
1051 .collect();
1052 out.push(row_data);
1053 Ok(())
1054 })?;
1055 Ok(Box::new(InMemoryRange::new(out)))
1056 }
1057 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
1058 let reference = self.reference_for_eval()?;
1059 let view = self
1060 .interp
1061 .context
1062 .resolve_range_view(&reference, self.interp.current_sheet())?;
1063 let (rows, cols) = view.dims();
1064 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
1065 view.for_each_row(&mut |row| {
1066 let row_data: Vec<LiteralValue> = (0..cols)
1067 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
1068 .collect();
1069 out.push(row_data);
1070 Ok(())
1071 })?;
1072 Ok(Box::new(InMemoryRange::new(out)))
1073 }
1074 ASTNodeType::Array(rows) => {
1075 let mut materialized = Vec::new();
1076 for row in rows {
1077 let mut materialized_row = Vec::new();
1078 for cell in row {
1079 materialized_row.push(self.interp.evaluate_ast(cell)?.into_literal());
1080 }
1081 materialized.push(materialized_row);
1082 }
1083 Ok(Box::new(InMemoryRange::new(materialized)))
1084 }
1085 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1086 .with_message(format!("Expected a range, got {:?}", node.node_type))),
1087 },
1088 ArgumentExpr::Arena { id, data_store, .. } => {
1089 let node = data_store.get_node(*id).ok_or_else(|| {
1090 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
1091 })?;
1092
1093 match node {
1094 crate::engine::arena::AstNodeData::Reference { .. }
1095 | crate::engine::arena::AstNodeData::Function { .. }
1096 | crate::engine::arena::AstNodeData::BinaryOp { .. } => {
1097 let reference = self.reference_for_eval()?;
1098 let view = self
1099 .interp
1100 .context
1101 .resolve_range_view(&reference, self.interp.current_sheet())?;
1102 let (rows, cols) = view.dims();
1103 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
1104 view.for_each_row(&mut |row| {
1105 let row_data: Vec<LiteralValue> = (0..cols)
1106 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
1107 .collect();
1108 out.push(row_data);
1109 Ok(())
1110 })?;
1111 Ok(Box::new(InMemoryRange::new(out)))
1112 }
1113 crate::engine::arena::AstNodeData::Array { .. } => {
1114 let (rows, cols, elements) =
1115 data_store.get_array_elems(*id).ok_or_else(|| {
1116 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
1117 })?;
1118 let rows_usize = rows as usize;
1119 let cols_usize = cols as usize;
1120 let mut materialized: Vec<Vec<LiteralValue>> =
1121 Vec::with_capacity(rows_usize);
1122 for r in 0..rows_usize {
1123 let mut row = Vec::with_capacity(cols_usize);
1124 for c in 0..cols_usize {
1125 let idx = r * cols_usize + c;
1126 let elem_id = elements.get(idx).copied().ok_or_else(|| {
1127 ExcelError::new(ExcelErrorKind::Value)
1128 .with_message("Invalid array")
1129 })?;
1130 let v = self.interp.evaluate_arena_ast(
1131 elem_id,
1132 data_store,
1133 self.sheet_registry(),
1134 )?;
1135 row.push(v.into_literal());
1136 }
1137 materialized.push(row);
1138 }
1139 Ok(Box::new(InMemoryRange::new(materialized)))
1140 }
1141 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1142 .with_message("Argument cannot be interpreted as a range.")),
1143 }
1144 }
1145 }
1146 }
1147
1148 fn sheet_registry(&self) -> &crate::engine::sheet_registry::SheetRegistry {
1149 match &self.expr {
1150 ArgumentExpr::Ast(_) => {
1151 unreachable!("sheet_registry only used for arena ArgumentHandle")
1153 }
1154 ArgumentExpr::Arena { sheet_registry, .. } => sheet_registry,
1155 }
1156 }
1157
1158 pub fn range_view(&self) -> Result<RangeView<'b>, ExcelError> {
1166 match self.resolve_once()? {
1167 ResolvedArgument::Range(view) => Ok(view),
1168 ResolvedArgument::ReferenceError(error) => Err(error),
1171 ResolvedArgument::Value(CalcValue::Range(view)) => {
1176 Ok(self.with_context_cancel_token(view))
1177 }
1178 ResolvedArgument::Value(CalcValue::Scalar(LiteralValue::Array(rows))) => {
1179 RangeView::try_from_owned_rows(
1180 rows,
1181 self.interp.context.date_system(),
1182 self.interp.context.cancellation_token(),
1183 )
1184 }
1185 ResolvedArgument::Value(_) => Err(ExcelError::new(ExcelErrorKind::Ref)
1186 .with_message("Argument cannot be interpreted as a range.")),
1187 }
1188 }
1189
1190 pub fn range_view_or_scalar(&self) -> Result<RangeView<'b>, ExcelError> {
1210 match self.resolve_once()? {
1211 ResolvedArgument::Range(view) => Ok(view),
1212 ResolvedArgument::ReferenceError(error) => Err(error),
1213 ResolvedArgument::Value(CalcValue::Range(view)) => {
1214 Ok(self.with_context_cancel_token(view))
1215 }
1216 ResolvedArgument::Value(CalcValue::Scalar(LiteralValue::Array(rows))) => {
1217 RangeView::try_from_owned_rows(
1218 rows,
1219 self.interp.context.date_system(),
1220 self.interp.context.cancellation_token(),
1221 )
1222 }
1223 ResolvedArgument::Value(CalcValue::Scalar(LiteralValue::Error(error))) => Err(error),
1226 ResolvedArgument::Value(
1227 CalcValue::Scalar(scalar) | CalcValue::AnnotatedScalar(scalar, _),
1228 ) => RangeView::try_from_owned_rows(
1229 vec![vec![scalar]],
1230 self.interp.context.date_system(),
1231 self.interp.context.cancellation_token(),
1232 ),
1233 ResolvedArgument::Value(CalcValue::Callable(_)) => {
1235 Err(ExcelError::new(ExcelErrorKind::Ref)
1236 .with_message("Argument cannot be interpreted as a range."))
1237 }
1238 }
1239 }
1240
1241 pub fn value_or_range(&self) -> Result<EvaluatedArg<'_>, ExcelError> {
1242 self.range().map(EvaluatedArg::Range).or_else(|_| {
1243 self.value()
1244 .map(|cv| EvaluatedArg::LiteralValue(Cow::Owned(cv.into_literal())))
1245 })
1246 }
1247
1248 pub fn lazy_values_owned(
1253 &'a self,
1254 ) -> Result<Box<dyn Iterator<Item = LiteralValue> + 'a>, ExcelError> {
1255 fn resolved_values<'a, 'b>(
1259 handle: &'a ArgumentHandle<'a, 'b>,
1260 ) -> Result<Box<dyn Iterator<Item = LiteralValue> + 'a>, ExcelError> {
1261 match handle.resolve_once()? {
1262 ResolvedArgument::Range(view) => {
1263 let mut values = Vec::new();
1264 view.for_each_cell(&mut |value| {
1265 values.push(value.clone());
1266 Ok(())
1267 })?;
1268 Ok(Box::new(values.into_iter()))
1269 }
1270 ResolvedArgument::ReferenceError(error) => Err(error),
1271 ResolvedArgument::Value(value) => {
1272 Ok(Box::new(std::iter::once(value.into_literal())))
1273 }
1274 }
1275 }
1276
1277 match &self.expr {
1278 ArgumentExpr::Ast(node) => match &node.node_type {
1279 ASTNodeType::Reference { .. } => resolved_values(self),
1280 ASTNodeType::Array(rows) => {
1281 struct ArrayEvalIter<'a, 'b> {
1282 rows: &'a [Vec<ASTNode>],
1283 r: usize,
1284 c: usize,
1285 interp: &'a Interpreter<'b>,
1286 }
1287 impl<'a, 'b> Iterator for ArrayEvalIter<'a, 'b> {
1288 type Item = LiteralValue;
1289 fn next(&mut self) -> Option<Self::Item> {
1290 if self.rows.is_empty() {
1291 return None;
1292 }
1293 let rows = self.rows;
1294 let mut r = self.r;
1295 let mut c = self.c;
1296 if r >= rows.len() {
1297 return None;
1298 }
1299 let node = &rows[r][c];
1300 c += 1;
1302 if c >= rows[r].len() {
1303 r += 1;
1304 c = 0;
1305 }
1306 self.r = r;
1307 self.c = c;
1308 match self.interp.evaluate_ast(node) {
1309 Ok(cv) => Some(cv.into_literal()),
1310 Err(e) => Some(LiteralValue::Error(e)),
1311 }
1312 }
1313 }
1314 let it = ArrayEvalIter {
1315 rows,
1316 r: 0,
1317 c: 0,
1318 interp: self.interp,
1319 };
1320 Ok(Box::new(it))
1321 }
1322 _ => {
1323 let v = self.value()?.into_literal();
1325 Ok(Box::new(std::iter::once(v)))
1326 }
1327 },
1328 ArgumentExpr::Arena {
1329 id,
1330 data_store,
1331 sheet_registry,
1332 } => {
1333 let node = data_store.get_node(*id).ok_or_else(|| {
1334 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
1335 })?;
1336
1337 match node {
1338 crate::engine::arena::AstNodeData::Reference { .. } => resolved_values(self),
1339 crate::engine::arena::AstNodeData::Array { .. } => {
1340 let (rows, cols, elements) =
1341 data_store.get_array_elems(*id).ok_or_else(|| {
1342 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
1343 })?;
1344
1345 struct ArenaArrayEvalIter<'a, 'b> {
1346 elements: &'a [crate::engine::arena::AstNodeId],
1347 idx: usize,
1348 interp: &'a Interpreter<'b>,
1349 data_store: &'a crate::engine::arena::DataStore,
1350 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
1351 }
1352
1353 impl<'a, 'b> Iterator for ArenaArrayEvalIter<'a, 'b> {
1354 type Item = LiteralValue;
1355
1356 fn next(&mut self) -> Option<Self::Item> {
1357 let id = self.elements.get(self.idx).copied()?;
1358 self.idx += 1;
1359 match self.interp.evaluate_arena_ast(
1360 id,
1361 self.data_store,
1362 self.sheet_registry,
1363 ) {
1364 Ok(cv) => Some(cv.into_literal()),
1365 Err(e) => Some(LiteralValue::Error(e)),
1366 }
1367 }
1368 }
1369
1370 let _ = (rows, cols);
1371 let it = ArenaArrayEvalIter {
1372 elements,
1373 idx: 0,
1374 interp: self.interp,
1375 data_store,
1376 sheet_registry,
1377 };
1378 Ok(Box::new(it))
1379 }
1380 _ => {
1381 let v = self
1382 .interp
1383 .evaluate_arena_ast(*id, data_store, sheet_registry)?;
1384 Ok(Box::new(std::iter::once(v.into_literal())))
1385 }
1386 }
1387 }
1388 }
1389 }
1390
1391 pub fn ast(&self) -> &ASTNode {
1392 match &self.expr {
1393 ArgumentExpr::Ast(node) => node,
1394 ArgumentExpr::Arena {
1395 id,
1396 data_store,
1397 sheet_registry,
1398 } => self.cached_ast.get_or_init(|| {
1399 data_store
1400 .retrieve_ast(*id, sheet_registry)
1401 .unwrap_or_else(|| ASTNode {
1402 node_type: ASTNodeType::Literal(LiteralValue::Error(
1403 ExcelError::new(ExcelErrorKind::Value)
1404 .with_message("Missing formula AST"),
1405 )),
1406 source_token: None,
1407 contains_volatile: false,
1408 })
1409 }),
1410 }
1411 }
1412
1413 pub fn as_reference(&self) -> Result<&ReferenceType, ExcelError> {
1416 match &self.expr {
1417 ArgumentExpr::Ast(node) => match &node.node_type {
1418 ASTNodeType::Reference { reference, .. } => {
1419 if let ReferenceType::NamedRange(name) = reference
1421 && let Some(local) = self.local_named_reference(name)
1422 {
1423 let bound = local?;
1424 return Ok(self.cached_ref.get_or_init(|| bound));
1425 }
1426 Ok(reference)
1427 }
1428 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1429 .with_message("Expected a reference (by-ref argument)")),
1430 },
1431 ArgumentExpr::Arena { .. } => {
1432 let reference = self.reference_for_eval()?;
1433 Ok(self.cached_ref.get_or_init(|| reference))
1434 }
1435 }
1436 }
1437
1438 pub fn as_reference_or_eval(&self) -> Result<ReferenceType, ExcelError> {
1441 match &self.expr {
1442 ArgumentExpr::Ast(node) => match &node.node_type {
1443 ASTNodeType::Reference { reference, .. } => {
1444 if let ReferenceType::NamedRange(name) = reference
1446 && let Some(local) = self.local_named_reference(name)
1447 {
1448 return local;
1449 }
1450 self.interp.reference_for_current_offset(reference)
1451 }
1452 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
1453 self.interp.evaluate_ast_as_reference(node)
1454 }
1455 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1456 .with_message("Argument is not a reference")),
1457 },
1458 ArgumentExpr::Arena {
1459 id,
1460 data_store,
1461 sheet_registry,
1462 } => {
1463 let node = data_store.get_node(*id).ok_or_else(|| {
1464 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
1465 })?;
1466
1467 match node {
1468 crate::engine::arena::AstNodeData::Reference { .. } => {
1469 self.reference_for_eval()
1470 }
1471 crate::engine::arena::AstNodeData::Function { .. }
1472 | crate::engine::arena::AstNodeData::BinaryOp { .. } => self
1473 .interp
1474 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry),
1475 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1476 .with_message("Argument is not a reference")),
1477 }
1478 }
1479 }
1480 }
1481
1482 pub fn matches_kind(&self, k: formualizer_common::ArgKind) -> Result<bool, ExcelError> {
1484 Ok(match k {
1485 formualizer_common::ArgKind::Any => true,
1486 formualizer_common::ArgKind::Range => self.range().is_ok(),
1487 formualizer_common::ArgKind::Number => matches!(
1488 self.value()?.into_literal(),
1489 LiteralValue::Number(_) | LiteralValue::Int(_)
1490 ),
1491 formualizer_common::ArgKind::Text => {
1492 matches!(self.value()?.into_literal(), LiteralValue::Text(_))
1493 }
1494 formualizer_common::ArgKind::Logical => {
1495 matches!(self.value()?.into_literal(), LiteralValue::Boolean(_))
1496 }
1497 })
1498 }
1499}
1500
1501#[derive(Debug, Clone)]
1503pub struct InMemoryRange {
1504 data: Vec<Vec<LiteralValue>>,
1505}
1506impl InMemoryRange {
1507 pub fn new(d: Vec<Vec<LiteralValue>>) -> Self {
1508 Self { data: d }
1509 }
1510}
1511impl Range for InMemoryRange {
1512 fn get(&self, r: usize, c: usize) -> Result<LiteralValue, ExcelError> {
1513 Ok(self
1514 .data
1515 .get(r)
1516 .and_then(|row| row.get(c))
1517 .cloned()
1518 .unwrap_or(LiteralValue::Empty))
1519 }
1520 fn dimensions(&self) -> (usize, usize) {
1521 (self.data.len(), self.data.first().map_or(0, |r| r.len()))
1522 }
1523 fn as_any(&self) -> &dyn Any {
1524 self
1525 }
1526}
1527
1528pub trait Table: Debug + Send + Sync {
1531 fn get_cell(&self, row: usize, column: &str) -> Result<LiteralValue, ExcelError>;
1532 fn get_column(&self, column: &str) -> Result<Box<dyn Range>, ExcelError>;
1533 fn columns(&self) -> Vec<String> {
1535 vec![]
1536 }
1537 fn data_height(&self) -> usize {
1539 0
1540 }
1541 fn has_headers(&self) -> bool {
1543 false
1544 }
1545 fn has_totals(&self) -> bool {
1547 false
1548 }
1549 fn headers_row(&self) -> Option<Box<dyn Range>> {
1551 None
1552 }
1553 fn totals_row(&self) -> Option<Box<dyn Range>> {
1555 None
1556 }
1557 fn data_body(&self) -> Option<Box<dyn Range>> {
1559 None
1560 }
1561 fn clone_box(&self) -> Box<dyn Table>;
1562}
1563impl Table for Box<dyn Table> {
1564 fn get_cell(&self, r: usize, c: &str) -> Result<LiteralValue, ExcelError> {
1565 (**self).get_cell(r, c)
1566 }
1567 fn get_column(&self, c: &str) -> Result<Box<dyn Range>, ExcelError> {
1568 (**self).get_column(c)
1569 }
1570 fn columns(&self) -> Vec<String> {
1571 (**self).columns()
1572 }
1573 fn data_height(&self) -> usize {
1574 (**self).data_height()
1575 }
1576 fn has_headers(&self) -> bool {
1577 (**self).has_headers()
1578 }
1579 fn has_totals(&self) -> bool {
1580 (**self).has_totals()
1581 }
1582 fn headers_row(&self) -> Option<Box<dyn Range>> {
1583 (**self).headers_row()
1584 }
1585 fn totals_row(&self) -> Option<Box<dyn Range>> {
1586 (**self).totals_row()
1587 }
1588 fn data_body(&self) -> Option<Box<dyn Range>> {
1589 (**self).data_body()
1590 }
1591 fn clone_box(&self) -> Box<dyn Table> {
1592 (**self).clone_box()
1593 }
1594}
1595
1596pub trait ReferenceResolver: Send + Sync {
1599 fn resolve_cell_reference(
1600 &self,
1601 sheet: Option<&str>,
1602 row: u32,
1603 col: u32,
1604 ) -> Result<LiteralValue, ExcelError>;
1605}
1606pub trait RangeResolver: Send + Sync {
1607 fn resolve_range_reference(
1608 &self,
1609 sheet: Option<&str>,
1610 sr: Option<u32>,
1611 sc: Option<u32>,
1612 er: Option<u32>,
1613 ec: Option<u32>,
1614 ) -> Result<Box<dyn Range>, ExcelError>;
1615}
1616pub trait NamedRangeResolver: Send + Sync {
1617 fn resolve_named_range_reference(
1618 &self,
1619 name: &str,
1620 ) -> Result<Vec<Vec<LiteralValue>>, ExcelError>;
1621}
1622pub trait TableResolver: Send + Sync {
1623 fn resolve_table_reference(
1624 &self,
1625 tref: &formualizer_parse::parser::TableReference,
1626 ) -> Result<Box<dyn Table>, ExcelError>;
1627}
1628
1629pub trait SourceResolver: Send + Sync {
1630 fn source_scalar_version(&self, _name: &str) -> Option<u64> {
1631 None
1632 }
1633
1634 fn resolve_source_scalar(&self, name: &str) -> Result<LiteralValue, ExcelError> {
1635 Err(ExcelError::new(ExcelErrorKind::NImpl)
1636 .with_message(format!("Source scalar not supported: {name}")))
1637 }
1638
1639 fn source_table_version(&self, _name: &str) -> Option<u64> {
1640 None
1641 }
1642
1643 fn resolve_source_table(&self, name: &str) -> Result<Box<dyn Table>, ExcelError> {
1644 Err(ExcelError::new(ExcelErrorKind::NImpl)
1645 .with_message(format!("Source table not supported: {name}")))
1646 }
1647}
1648
1649pub trait Resolver: ReferenceResolver + RangeResolver + NamedRangeResolver + TableResolver {
1650 fn resolve_range_like(&self, r: &ReferenceType) -> Result<Box<dyn Range>, ExcelError> {
1651 match r {
1652 ReferenceType::Range {
1653 sheet,
1654 start_row,
1655 start_col,
1656 end_row,
1657 end_col,
1658 ..
1659 } => self.resolve_range_reference(
1660 sheet.as_deref(),
1661 *start_row,
1662 *start_col,
1663 *end_row,
1664 *end_col,
1665 ),
1666 ReferenceType::External(_) => Err(ExcelError::new(ExcelErrorKind::NImpl)
1667 .with_message("External references are not supported by Resolver".to_string())),
1668 ReferenceType::Table(tref) => {
1669 let t = self.resolve_table_reference(tref)?;
1670 match &tref.specifier {
1671 Some(TableSpecifier::Column(c)) => t.get_column(c),
1672 Some(TableSpecifier::ColumnRange(start, end)) => {
1673 let cols = t.columns();
1675 let start_key = start.to_lowercase();
1676 let end_key = end.to_lowercase();
1677 let start_idx = cols.iter().position(|n| n.to_lowercase() == start_key);
1678 let end_idx = cols.iter().position(|n| n.to_lowercase() == end_key);
1679 if let (Some(mut si), Some(mut ei)) = (start_idx, end_idx) {
1680 if si > ei {
1681 std::mem::swap(&mut si, &mut ei);
1682 }
1683 let h = t.data_height();
1685 let w = ei - si + 1;
1686 let mut rows = vec![vec![LiteralValue::Empty; w]; h];
1687 for (offset, ci) in (si..=ei).enumerate() {
1688 let cname = &cols[ci];
1689 let col_range = t.get_column(cname)?;
1690 let (rh, _) = col_range.dimensions();
1691 for (r, row) in rows.iter_mut().enumerate().take(h.min(rh)) {
1692 row[offset] = col_range.get(r, 0)?;
1693 }
1694 }
1695 Ok(Box::new(InMemoryRange::new(rows)))
1696 } else {
1697 Err(ExcelError::new(ExcelErrorKind::Ref).with_message(
1698 "Column range refers to unknown column(s)".to_string(),
1699 ))
1700 }
1701 }
1702 Some(TableSpecifier::SpecialItem(
1703 formualizer_parse::parser::SpecialItem::Headers,
1704 )) => {
1705 if let Some(h) = t.headers_row() {
1706 Ok(h)
1707 } else {
1708 Ok(Box::new(InMemoryRange::new(vec![])))
1709 }
1710 }
1711 Some(TableSpecifier::SpecialItem(
1712 formualizer_parse::parser::SpecialItem::Totals,
1713 )) => {
1714 if let Some(tr) = t.totals_row() {
1715 Ok(tr)
1716 } else {
1717 Ok(Box::new(InMemoryRange::new(vec![])))
1718 }
1719 }
1720 Some(TableSpecifier::SpecialItem(
1721 formualizer_parse::parser::SpecialItem::Data,
1722 )) => {
1723 if let Some(body) = t.data_body() {
1724 Ok(body)
1725 } else {
1726 Ok(Box::new(InMemoryRange::new(vec![])))
1727 }
1728 }
1729 Some(TableSpecifier::SpecialItem(
1730 formualizer_parse::parser::SpecialItem::All,
1731 )) => {
1732 let mut out: Vec<Vec<LiteralValue>> = Vec::new();
1734 if let Some(h) = t.headers_row() {
1735 out.extend(h.iter_rows());
1736 }
1737 if let Some(body) = t.data_body() {
1738 out.extend(body.iter_rows());
1739 }
1740 if let Some(tr) = t.totals_row() {
1741 out.extend(tr.iter_rows());
1742 }
1743 Ok(Box::new(InMemoryRange::new(out)))
1744 }
1745 Some(TableSpecifier::SpecialItem(
1746 formualizer_parse::parser::SpecialItem::ThisRow,
1747 )) => Err(ExcelError::new(ExcelErrorKind::NImpl).with_message(
1748 "@ (This Row) requires table-aware context; not yet supported".to_string(),
1749 )),
1750 Some(TableSpecifier::All) => {
1751 let mut out: Vec<Vec<LiteralValue>> = Vec::new();
1753 if let Some(h) = t.headers_row() {
1754 out.extend(h.iter_rows());
1755 }
1756 if let Some(body) = t.data_body() {
1757 out.extend(body.iter_rows());
1758 }
1759 if let Some(tr) = t.totals_row() {
1760 out.extend(tr.iter_rows());
1761 }
1762 Ok(Box::new(InMemoryRange::new(out)))
1763 }
1764 Some(TableSpecifier::Data) => {
1765 if let Some(body) = t.data_body() {
1766 Ok(body)
1767 } else {
1768 Ok(Box::new(InMemoryRange::new(vec![])))
1769 }
1770 }
1771 Some(TableSpecifier::Combination(_)) => Err(ExcelError::new(
1773 ExcelErrorKind::NImpl,
1774 )
1775 .with_message("Complex structured references not yet supported".to_string())),
1776 Some(TableSpecifier::Row(_)) => Err(ExcelError::new(ExcelErrorKind::NImpl)
1777 .with_message("Row selectors (@/index) not yet supported".to_string())),
1778 Some(TableSpecifier::Headers) | Some(TableSpecifier::Totals) => {
1779 Err(ExcelError::new(ExcelErrorKind::NImpl).with_message(
1780 "Legacy Headers/Totals variants not used; use SpecialItem".to_string(),
1781 ))
1782 }
1783 None => Err(ExcelError::new(ExcelErrorKind::Ref).with_message(
1784 "Table reference without specifier is unsupported".to_string(),
1785 )),
1786 }
1787 }
1788 ReferenceType::NamedRange(n) => {
1789 let v = self.resolve_named_range_reference(n)?;
1790 Ok(Box::new(InMemoryRange::new(v)))
1791 }
1792 ReferenceType::Cell {
1793 sheet, row, col, ..
1794 } => {
1795 let v = self.resolve_cell_reference(sheet.as_deref(), *row, *col)?;
1796 Ok(Box::new(InMemoryRange::new(vec![vec![v]])))
1797 }
1798 ReferenceType::Cell3D { .. } | ReferenceType::Range3D { .. } => {
1799 Err(ExcelError::new(ExcelErrorKind::NImpl)
1800 .with_message("3D references are not yet supported".to_string()))
1801 }
1802 }
1803 }
1804}
1805
1806pub trait FunctionProvider: Send + Sync {
1809 fn get_function(&self, ns: &str, name: &str) -> Option<Arc<dyn Function>>;
1810
1811 #[doc(hidden)]
1812 fn get_function_for_planning(&self, _ns: &str, _name: &str) -> Option<Arc<dyn Function>> {
1813 None
1814 }
1815
1816 #[doc(hidden)]
1819 fn planning_semantic_revision(&self) -> Option<u64> {
1820 None
1821 }
1822
1823 #[doc(hidden)]
1824 fn function_capabilities(&self, ns: &str, name: &str) -> Option<crate::function::FnCaps> {
1825 self.get_function(ns, name).map(|function| function.caps())
1826 }
1827
1828 fn function_semantic_identity(
1829 &self,
1830 ns: &str,
1831 name: &str,
1832 arity: usize,
1833 ) -> Option<crate::function_contract::FunctionSemanticIdentity> {
1834 crate::function_registry::resolve_semantic_identity(self, ns, name, arity)
1835 }
1836}
1837
1838pub trait EvaluationContext: Resolver + FunctionProvider + SourceResolver {
1839 fn thread_pool(&self) -> Option<&Arc<rayon::ThreadPool>> {
1842 None
1843 }
1844
1845 fn cancellation_token(&self) -> Option<crate::engine::CancelToken> {
1852 None
1853 }
1854
1855 fn chunk_hint(&self) -> Option<usize> {
1857 None
1858 }
1859
1860 fn resolve_range_view<'c>(
1863 &'c self,
1864 _reference: &ReferenceType,
1865 _current_sheet: &str,
1866 ) -> Result<RangeView<'c>, ExcelError> {
1867 Err(ExcelError::new(ExcelErrorKind::NImpl))
1868 }
1869
1870 fn resolve_cell_reference_value(
1875 &self,
1876 sheet: Option<&str>,
1877 row: u32,
1878 col: u32,
1879 current_sheet: &str,
1880 ) -> Result<LiteralValue, ExcelError> {
1881 let reference = ReferenceType::Cell {
1882 sheet: sheet.map(str::to_string),
1883 row,
1884 col,
1885 row_abs: true,
1886 col_abs: true,
1887 };
1888 let view = self.resolve_range_view(&reference, current_sheet)?;
1889 Ok(view.as_1x1().unwrap_or(LiteralValue::Empty))
1890 }
1891
1892 fn resolve_cell_format(
1894 &self,
1895 _sheet: Option<&str>,
1896 _row: u32,
1897 _col: u32,
1898 _current_sheet: &str,
1899 ) -> Option<crate::format::FormatId> {
1900 None
1901 }
1902
1903 #[doc(hidden)]
1908 fn resolve_cell_reference_value_formatted(
1909 &self,
1910 sheet: Option<&str>,
1911 row: u32,
1912 col: u32,
1913 current_sheet: &str,
1914 ) -> Result<(LiteralValue, Option<crate::format::FormatId>), ExcelError> {
1915 let value = self.resolve_cell_reference_value(sheet, row, col, current_sheet)?;
1916 Ok((
1917 value,
1918 self.resolve_cell_format(sheet, row, col, current_sheet),
1919 ))
1920 }
1921
1922 fn format_class(
1924 &self,
1925 format: crate::format::FormatId,
1926 ) -> Option<formualizer_common::numfmt::FormatClass> {
1927 formualizer_common::numfmt::NumberFormat::builtin(format.0)
1928 .map(|format| format.class().clone())
1929 }
1930
1931 fn record_cell_derived_format(
1933 &self,
1934 _sheet: &str,
1935 _row: u32,
1936 _col: u32,
1937 _format: Option<crate::format::FormatId>,
1938 ) {
1939 }
1940
1941 fn locale(&self) -> crate::locale::Locale {
1943 crate::locale::Locale::invariant()
1944 }
1945
1946 fn workbook_sheet_count(&self) -> Option<usize> {
1948 None
1949 }
1950
1951 fn sheet_index_by_name(&self, _sheet: &str) -> Option<usize> {
1953 None
1954 }
1955
1956 fn current_sheet_index(&self, current_sheet: &str) -> Option<usize> {
1958 self.sheet_index_by_name(current_sheet)
1959 }
1960
1961 fn inspect_reference(
1963 &self,
1964 _reference: &ReferenceType,
1965 _current_sheet: &str,
1966 ) -> Result<Option<ReferenceInfo>, ExcelError> {
1967 Ok(None)
1968 }
1969
1970 fn formula_text_at_cell(&self, _cell: CellRef) -> Result<Option<String>, ExcelError> {
1972 Ok(None)
1973 }
1974
1975 fn clock(&self) -> &dyn crate::timezone::ClockProvider {
1984 #[cfg(feature = "system-clock")]
1985 {
1986 static DEFAULT_CLOCK: std::sync::OnceLock<crate::timezone::SystemClock> =
1987 std::sync::OnceLock::new();
1988 DEFAULT_CLOCK.get_or_init(|| {
1989 crate::timezone::SystemClock::new(crate::timezone::TimeZoneSpec::default())
1990 })
1991 }
1992 #[cfg(not(feature = "system-clock"))]
1993 {
1994 static DEFAULT_CLOCK: std::sync::OnceLock<crate::timezone::FixedClock> =
1995 std::sync::OnceLock::new();
1996 DEFAULT_CLOCK.get_or_init(|| {
1997 crate::timezone::FixedClock::new(
1998 chrono::DateTime::UNIX_EPOCH,
1999 crate::timezone::TimeZoneSpec::Utc,
2000 )
2001 })
2002 }
2003 }
2004
2005 fn timezone(&self) -> &crate::timezone::TimeZoneSpec {
2009 self.clock().timezone()
2010 }
2011
2012 fn volatile_level(&self) -> VolatileLevel {
2014 VolatileLevel::Always
2015 }
2016
2017 fn workbook_seed(&self) -> u64 {
2019 0xF0F0_D0D0_AAAA_5555
2020 }
2021
2022 fn recalc_epoch(&self) -> u64 {
2024 0
2025 }
2026
2027 fn used_rows_for_columns(
2032 &self,
2033 _sheet: &str,
2034 _start_col: u32,
2035 _end_col: u32,
2036 ) -> Option<(u32, u32)> {
2037 None
2038 }
2039
2040 fn used_cols_for_rows(
2043 &self,
2044 _sheet: &str,
2045 _start_row: u32,
2046 _end_row: u32,
2047 ) -> Option<(u32, u32)> {
2048 None
2049 }
2050
2051 fn sheet_bounds(&self, _sheet: &str) -> Option<(u32, u32)> {
2053 None
2054 }
2055
2056 fn data_snapshot_id(&self) -> u64 {
2058 0
2059 }
2060
2061 fn backend_caps(&self) -> BackendCaps {
2063 BackendCaps::default()
2064 }
2065
2066 fn date_system(&self) -> crate::engine::DateSystem {
2071 crate::engine::DateSystem::Excel1900
2072 }
2073
2074 fn build_lookup_index(
2077 &self,
2078 _view: &RangeView<'_>,
2079 _axis: LookupAxis,
2080 ) -> Option<std::sync::Arc<LookupIndex>> {
2081 None
2082 }
2083
2084 fn build_criteria_mask(
2087 &self,
2088 _view: &RangeView<'_>,
2089 _col_in_view: usize,
2090 _pred: &crate::args::CriteriaPredicate,
2091 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2092 None
2093 }
2094
2095 fn build_row_visibility_mask(
2098 &self,
2099 _view: &RangeView<'_>,
2100 _mode: VisibilityMaskMode,
2101 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2102 None
2103 }
2104}
2105
2106#[derive(Copy, Clone, Debug, Default)]
2108pub struct BackendCaps {
2109 pub streaming: bool,
2111 pub used_region: bool,
2113 pub write: bool,
2115 pub tables: bool,
2117 pub async_stream: bool,
2119}
2120
2121#[derive(Copy, Clone, Debug, Eq, PartialEq)]
2124pub enum VolatileLevel {
2125 Always,
2127 OnRecalc,
2129 OnOpen,
2131}
2132
2133pub trait FunctionContext<'ctx> {
2135 fn locale(&self) -> crate::locale::Locale;
2136 fn timezone(&self) -> &crate::timezone::TimeZoneSpec;
2137 fn clock(&self) -> &dyn crate::timezone::ClockProvider;
2138 fn thread_pool(&self) -> Option<&std::sync::Arc<rayon::ThreadPool>>;
2139 fn cancellation_token(&self) -> Option<crate::engine::CancelToken>;
2145 fn chunk_hint(&self) -> Option<usize>;
2146
2147 fn current_sheet(&self) -> &str;
2149
2150 fn workbook_sheet_count(&self) -> Option<usize> {
2151 None
2152 }
2153
2154 fn sheet_index_by_name(&self, _sheet: &str) -> Option<usize> {
2155 None
2156 }
2157
2158 fn current_sheet_index(&self) -> Option<usize> {
2159 self.sheet_index_by_name(self.current_sheet())
2160 }
2161
2162 fn inspect_reference(
2163 &self,
2164 _reference: &ReferenceType,
2165 ) -> Result<Option<ReferenceInfo>, ExcelError> {
2166 Ok(None)
2167 }
2168
2169 fn formula_text_at_cell(&self, _cell: CellRef) -> Result<Option<String>, ExcelError> {
2170 Ok(None)
2171 }
2172
2173 fn volatile_level(&self) -> VolatileLevel;
2174 fn workbook_seed(&self) -> u64;
2175 fn recalc_epoch(&self) -> u64;
2176 fn current_cell(&self) -> Option<CellRef>;
2177
2178 fn resolve_range_view(
2180 &self,
2181 _reference: &ReferenceType,
2182 _current_sheet: &str,
2183 ) -> Result<RangeView<'ctx>, ExcelError>;
2184
2185 fn rng_for_current(&self, fn_salt: u64) -> rand::rngs::SmallRng {
2189 use crate::rng::{compose_seed, small_rng_from_lanes};
2190 let (sheet_id, row, col) = self
2191 .current_cell()
2192 .map(|c| (c.sheet_id as u32, c.coord.row(), c.coord.col()))
2193 .unwrap_or((0, 0, 0));
2194 let epoch = match self.volatile_level() {
2196 VolatileLevel::OnRecalc => self.recalc_epoch(),
2197 _ => 0,
2198 };
2199 let (l0, l1) = compose_seed(self.workbook_seed(), sheet_id, row, col, fn_salt, epoch);
2200 small_rng_from_lanes(l0, l1)
2201 }
2202
2203 fn date_system(&self) -> crate::engine::DateSystem {
2205 crate::engine::DateSystem::Excel1900
2206 }
2207
2208 fn get_lookup_index(
2211 &self,
2212 _view: &RangeView<'_>,
2213 _axis: LookupAxis,
2214 ) -> Option<std::sync::Arc<LookupIndex>> {
2215 None
2216 }
2217
2218 fn get_criteria_mask(
2221 &self,
2222 _view: &RangeView<'_>,
2223 _col_in_view: usize,
2224 _pred: &crate::args::CriteriaPredicate,
2225 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2226 None
2227 }
2228
2229 fn get_row_visibility_mask(
2231 &self,
2232 _view: &RangeView<'_>,
2233 _mode: VisibilityMaskMode,
2234 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2235 None
2236 }
2237}
2238
2239pub struct DefaultFunctionContext<'a> {
2241 pub base: &'a dyn EvaluationContext,
2242 pub current: Option<CellRef>,
2243 pub current_sheet: &'a str,
2244}
2245
2246impl<'a> DefaultFunctionContext<'a> {
2247 pub fn new(
2248 base: &'a dyn EvaluationContext,
2249 current: Option<CellRef>,
2250 current_sheet: &'a str,
2251 ) -> Self {
2252 Self {
2253 base,
2254 current,
2255 current_sheet,
2256 }
2257 }
2258
2259 pub fn new_with_sheet(
2260 base: &'a dyn EvaluationContext,
2261 current: Option<CellRef>,
2262 current_sheet: &'a str,
2263 ) -> Self {
2264 Self::new(base, current, current_sheet)
2265 }
2266}
2267
2268impl<'a> FunctionContext<'a> for DefaultFunctionContext<'a> {
2269 fn locale(&self) -> crate::locale::Locale {
2270 self.base.locale()
2271 }
2272
2273 fn current_sheet(&self) -> &str {
2274 self.current_sheet
2275 }
2276
2277 fn workbook_sheet_count(&self) -> Option<usize> {
2278 self.base.workbook_sheet_count()
2279 }
2280
2281 fn sheet_index_by_name(&self, sheet: &str) -> Option<usize> {
2282 self.base.sheet_index_by_name(sheet)
2283 }
2284
2285 fn current_sheet_index(&self) -> Option<usize> {
2286 self.base.current_sheet_index(self.current_sheet)
2287 }
2288
2289 fn inspect_reference(
2290 &self,
2291 reference: &ReferenceType,
2292 ) -> Result<Option<ReferenceInfo>, ExcelError> {
2293 self.base.inspect_reference(reference, self.current_sheet)
2294 }
2295
2296 fn formula_text_at_cell(&self, cell: CellRef) -> Result<Option<String>, ExcelError> {
2297 self.base.formula_text_at_cell(cell)
2298 }
2299
2300 fn timezone(&self) -> &crate::timezone::TimeZoneSpec {
2301 self.base.timezone()
2302 }
2303
2304 fn clock(&self) -> &dyn crate::timezone::ClockProvider {
2305 self.base.clock()
2306 }
2307 fn thread_pool(&self) -> Option<&std::sync::Arc<rayon::ThreadPool>> {
2308 self.base.thread_pool()
2309 }
2310 fn cancellation_token(&self) -> Option<crate::engine::CancelToken> {
2311 self.base.cancellation_token()
2312 }
2313 fn chunk_hint(&self) -> Option<usize> {
2314 self.base.chunk_hint()
2315 }
2316
2317 fn volatile_level(&self) -> VolatileLevel {
2318 self.base.volatile_level()
2319 }
2320 fn workbook_seed(&self) -> u64 {
2321 self.base.workbook_seed()
2322 }
2323 fn recalc_epoch(&self) -> u64 {
2324 self.base.recalc_epoch()
2325 }
2326 fn current_cell(&self) -> Option<CellRef> {
2327 self.current
2328 }
2329
2330 fn resolve_range_view(
2331 &self,
2332 reference: &ReferenceType,
2333 current_sheet: &str,
2334 ) -> Result<RangeView<'a>, ExcelError> {
2335 self.base.resolve_range_view(reference, current_sheet)
2336 }
2337
2338 fn date_system(&self) -> crate::engine::DateSystem {
2341 self.base.date_system()
2342 }
2343
2344 fn get_lookup_index(
2345 &self,
2346 view: &RangeView<'_>,
2347 axis: LookupAxis,
2348 ) -> Option<std::sync::Arc<LookupIndex>> {
2349 self.base.build_lookup_index(view, axis)
2350 }
2351
2352 fn get_criteria_mask(
2353 &self,
2354 view: &RangeView<'_>,
2355 col_in_view: usize,
2356 pred: &crate::args::CriteriaPredicate,
2357 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2358 self.base.build_criteria_mask(view, col_in_view, pred)
2359 }
2360
2361 fn get_row_visibility_mask(
2362 &self,
2363 view: &RangeView<'_>,
2364 mode: VisibilityMaskMode,
2365 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2366 self.base.build_row_visibility_mask(view, mode)
2367 }
2368}