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
179impl<'a> CalcValue<'a> {
180 pub fn into_literal(self) -> LiteralValue {
181 match self {
182 CalcValue::Scalar(s) | CalcValue::AnnotatedScalar(s, _) => s,
183 CalcValue::Range(rv) => {
184 let (rows, cols) = rv.dims();
185 if rows == 1 && cols == 1 {
186 rv.get_cell(0, 0)
187 } else {
188 let mut data = Vec::with_capacity(rows);
189 for row_idx in 0..rows {
190 let mut row = Vec::with_capacity(cols);
191 for col_idx in 0..cols {
192 row.push(rv.get_cell(row_idx, col_idx));
193 }
194 data.push(row);
195 }
196 LiteralValue::Array(data)
197 }
198 }
199 CalcValue::Callable(_) => LiteralValue::Error(
200 ExcelError::new(ExcelErrorKind::Calc).with_message("LAMBDA value must be invoked"),
201 ),
202 }
203 }
204
205 pub fn as_scalar(&self) -> Option<&LiteralValue> {
206 match self {
207 CalcValue::Scalar(s) | CalcValue::AnnotatedScalar(s, _) => Some(s),
208 _ => None,
209 }
210 }
211
212 pub fn format_id(&self) -> Option<crate::format::FormatId> {
213 match self {
214 CalcValue::AnnotatedScalar(_, format) => Some(*format),
215 _ => None,
216 }
217 }
218
219 pub fn with_format(self, format: Option<crate::format::FormatId>) -> Self {
220 let format = format.filter(|id| *id != crate::format::FormatId::GENERAL);
221 match (self, format) {
222 (CalcValue::Scalar(value) | CalcValue::AnnotatedScalar(value, _), Some(id)) => {
223 CalcValue::AnnotatedScalar(value, id)
224 }
225 (CalcValue::AnnotatedScalar(value, _), None) => CalcValue::Scalar(value),
226 (other, _) => other,
227 }
228 }
229
230 pub fn into_scalar_parts(self) -> (LiteralValue, Option<crate::format::FormatId>) {
231 match self {
232 CalcValue::Scalar(value) => (value, None),
233 CalcValue::AnnotatedScalar(value, format) => (value, Some(format)),
234 other => (other.into_literal(), None),
235 }
236 }
237
238 pub fn as_range(&self) -> Option<&RangeView<'a>> {
239 match self {
240 CalcValue::Range(r) => Some(r),
241 _ => None,
242 }
243 }
244
245 pub fn as_callable(&self) -> Option<&Arc<dyn CustomCallable>> {
246 match self {
247 CalcValue::Callable(c) => Some(c),
248 _ => None,
249 }
250 }
251
252 pub fn into_owned(self) -> LiteralValue {
253 self.into_literal()
254 }
255}
256
257impl From<CalcValue<'_>> for LiteralValue {
258 fn from(val: CalcValue<'_>) -> Self {
259 val.into_literal()
260 }
261}
262
263impl<'a> PartialEq<LiteralValue> for CalcValue<'a> {
264 fn eq(&self, other: &LiteralValue) -> bool {
265 match self {
266 CalcValue::Scalar(s) | CalcValue::AnnotatedScalar(s, _) => s == other,
267 CalcValue::Range(rv) => match other {
268 LiteralValue::Array(arr) => {
269 let (rows, cols) = rv.dims();
270 if arr.len() != rows {
271 return false;
272 }
273 for (r, row) in arr.iter().enumerate() {
274 if row.len() != cols {
275 return false;
276 }
277 for (c, cell) in row.iter().enumerate() {
278 if &rv.get_cell(r, c) != cell {
279 return false;
280 }
281 }
282 }
283 true
284 }
285 _ => {
286 let (rows, cols) = rv.dims();
287 rows == 1 && cols == 1 && &rv.get_cell(0, 0) == other
288 }
289 },
290 CalcValue::Callable(_) => false,
291 }
292 }
293}
294
295impl<'a> PartialEq<CalcValue<'a>> for LiteralValue {
296 fn eq(&self, other: &CalcValue<'a>) -> bool {
297 other == self
298 }
299}
300
301pub enum EvaluatedArg<'a> {
302 LiteralValue(CowValue<'a>),
303 Range(Box<dyn Range>),
304}
305
306enum ArgumentExpr<'a> {
307 Ast(&'a ASTNode),
308 Arena {
309 id: crate::engine::arena::AstNodeId,
310 data_store: &'a crate::engine::arena::DataStore,
311 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
312 },
313}
314
315pub struct ArgumentHandle<'a, 'b> {
316 expr: ArgumentExpr<'a>,
317 interp: &'a Interpreter<'b>,
318 cached_ast: std::cell::OnceCell<ASTNode>,
319 cached_ref: std::cell::OnceCell<ReferenceType>,
320 cached_reference_or_value:
321 std::cell::OnceCell<Result<crate::function::FunctionResolution<'b>, ExcelError>>,
322 cached_resolved: std::cell::OnceCell<Result<ResolvedArgument<'b>, ExcelError>>,
323 cached_value: std::cell::OnceCell<Result<crate::traits::CalcValue<'b>, ExcelError>>,
332}
333
334impl<'a, 'b> ArgumentHandle<'a, 'b> {
335 pub(crate) fn new(node: &'a ASTNode, interp: &'a Interpreter<'b>) -> Self {
336 Self {
337 expr: ArgumentExpr::Ast(node),
338 interp,
339 cached_ast: std::cell::OnceCell::new(),
340 cached_ref: std::cell::OnceCell::new(),
341 cached_reference_or_value: std::cell::OnceCell::new(),
342 cached_resolved: std::cell::OnceCell::new(),
343 cached_value: std::cell::OnceCell::new(),
344 }
345 }
346
347 pub(crate) fn new_arena(
348 id: crate::engine::arena::AstNodeId,
349 interp: &'a Interpreter<'b>,
350 data_store: &'a crate::engine::arena::DataStore,
351 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
352 ) -> Self {
353 Self {
354 expr: ArgumentExpr::Arena {
355 id,
356 data_store,
357 sheet_registry,
358 },
359 interp,
360 cached_ast: std::cell::OnceCell::new(),
361 cached_ref: std::cell::OnceCell::new(),
362 cached_reference_or_value: std::cell::OnceCell::new(),
363 cached_resolved: std::cell::OnceCell::new(),
364 cached_value: std::cell::OnceCell::new(),
365 }
366 }
367
368 pub(crate) fn date_system(&self) -> crate::engine::DateSystem {
374 self.interp.context.date_system()
375 }
376
377 pub fn is_omitted(&self) -> bool {
381 match &self.expr {
382 ArgumentExpr::Ast(node) => matches!(node.node_type, ASTNodeType::Omitted),
383 ArgumentExpr::Arena { id, data_store, .. } => matches!(
384 data_store.get_node(*id),
385 Some(crate::engine::arena::AstNodeData::Omitted)
386 ),
387 }
388 }
389
390 pub(crate) fn bare_reference(&self) -> Option<ReferenceType> {
403 let is_reference = match &self.expr {
404 ArgumentExpr::Ast(node) => matches!(node.node_type, ASTNodeType::Reference { .. }),
405 ArgumentExpr::Arena { id, data_store, .. } => matches!(
406 data_store.get_node(*id),
407 Some(crate::engine::arena::AstNodeData::Reference { .. })
408 ),
409 };
410 if !is_reference {
411 return None;
412 }
413 self.as_reference_or_eval().ok()
414 }
415
416 pub(crate) fn has_reference_semantics(&self) -> bool {
422 self.reference_attempt().is_some()
423 }
424
425 pub(crate) fn may_return_reference(&self) -> bool {
430 match &self.expr {
431 ArgumentExpr::Ast(node) => match &node.node_type {
432 ASTNodeType::Reference { reference, .. } => match reference {
433 ReferenceType::NamedRange(name)
435 if self.interp.resolve_local_name(name).is_some() =>
436 {
437 self.interp.resolve_local_bound_reference(name).is_some()
438 }
439 _ => true,
440 },
441 ASTNodeType::BinaryOp { op, .. } => op == ":",
442 ASTNodeType::Function { name, .. } => self
443 .interp
444 .context
445 .function_capabilities("", name)
446 .is_some_and(|caps| caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)),
447 _ => false,
448 },
449 ArgumentExpr::Arena { id, data_store, .. } => match data_store.get_node(*id) {
450 Some(crate::engine::arena::AstNodeData::Reference { ref_type, .. }) => {
451 match ref_type {
452 crate::engine::arena::CompactRefType::NamedRange(name_id)
454 if self
455 .interp
456 .resolve_local_name(data_store.resolve_ast_string(*name_id))
457 .is_some() =>
458 {
459 self.interp
460 .resolve_local_bound_reference(
461 data_store.resolve_ast_string(*name_id),
462 )
463 .is_some()
464 }
465 _ => true,
466 }
467 }
468 Some(crate::engine::arena::AstNodeData::BinaryOp { op_id, .. }) => {
469 data_store.resolve_ast_string(*op_id) == ":"
470 }
471 Some(crate::engine::arena::AstNodeData::Function { name_id, .. }) => self
472 .interp
473 .context
474 .function_capabilities("", data_store.resolve_ast_string(*name_id))
475 .is_some_and(|caps| caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)),
476 _ => false,
477 },
478 }
479 }
480
481 pub fn value(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
482 self.cached_value
483 .get_or_init(|| self.compute_value())
484 .clone()
485 }
486
487 pub(crate) fn value_for_text(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
493 if self.is_omitted() {
494 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(
495 String::new(),
496 )))
497 } else {
498 self.value()
499 }
500 }
501
502 pub(crate) fn resolve_once_for_text(&self) -> Result<ResolvedArgument<'b>, ExcelError> {
503 if self.is_omitted() {
504 Ok(ResolvedArgument::Value(crate::traits::CalcValue::Scalar(
505 LiteralValue::Text(String::new()),
506 )))
507 } else {
508 self.resolve_once()
509 }
510 }
511
512 fn compute_value(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
513 match &self.expr {
514 ArgumentExpr::Ast(node) => match &node.node_type {
515 ASTNodeType::Literal(v) => Ok(crate::traits::CalcValue::Scalar(v.clone())),
516 ASTNodeType::Omitted => {
519 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
520 }
521 _ => self.interp.evaluate_ast(node),
522 },
523 ArgumentExpr::Arena {
524 id,
525 data_store,
526 sheet_registry,
527 } => {
528 if matches!(
529 data_store.get_node(*id),
530 Some(crate::engine::arena::AstNodeData::Omitted)
531 ) {
532 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
533 } else {
534 self.interp
535 .evaluate_arena_ast(*id, data_store, sheet_registry)
536 }
537 }
538 }
539 }
540
541 pub fn value_with_env(
542 &self,
543 env: crate::interpreter::LocalEnv,
544 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
545 let scoped = self.interp.with_local_env(env);
546 match &self.expr {
547 ArgumentExpr::Ast(node) => match &node.node_type {
548 ASTNodeType::Literal(v) => Ok(crate::traits::CalcValue::Scalar(v.clone())),
549 ASTNodeType::Omitted => {
550 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
551 }
552 _ => scoped.evaluate_ast(node),
553 },
554 ArgumentExpr::Arena {
555 id,
556 data_store,
557 sheet_registry,
558 } => {
559 if matches!(
560 data_store.get_node(*id),
561 Some(crate::engine::arena::AstNodeData::Omitted)
562 ) {
563 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
564 } else {
565 scoped.evaluate_arena_ast(*id, data_store, sheet_registry)
566 }
567 }
568 }
569 }
570
571 pub fn current_env(&self) -> crate::interpreter::LocalEnv {
572 self.interp.local_env().clone()
573 }
574
575 pub(crate) fn bound_reference_in_env(
582 &self,
583 env: &crate::interpreter::LocalEnv,
584 ) -> Option<ReferenceType> {
585 match &self.expr {
586 ArgumentExpr::Ast(node) => match &node.node_type {
587 ASTNodeType::Reference { reference, .. } => {
588 if let ReferenceType::NamedRange(name) = reference
589 && let Some(binding) = env.lookup(name)
590 {
591 return match binding {
593 crate::interpreter::LocalBinding::ValueWithReference {
594 reference,
595 ..
596 } => Some(reference),
597 _ => None,
598 };
599 }
600 self.interp.reference_for_current_offset(reference).ok()
601 }
602 ASTNodeType::BinaryOp { op, .. } if op == ":" => self
603 .interp
604 .with_local_env(env.clone())
605 .evaluate_ast_as_reference(node)
606 .ok(),
607 _ => None,
608 },
609 ArgumentExpr::Arena {
610 id,
611 data_store,
612 sheet_registry,
613 } => match data_store.get_node(*id) {
614 Some(crate::engine::arena::AstNodeData::Reference { ref_type, .. }) => {
615 if let crate::engine::arena::CompactRefType::NamedRange(name_id) = ref_type
616 && let Some(binding) = env.lookup(data_store.resolve_ast_string(*name_id))
617 {
618 return match binding {
619 crate::interpreter::LocalBinding::ValueWithReference {
620 reference,
621 ..
622 } => Some(reference),
623 _ => None,
624 };
625 }
626 let reference =
627 data_store.reconstruct_reference_type_for_eval(ref_type, sheet_registry);
628 self.interp.reference_for_current_offset(&reference).ok()
629 }
630 Some(crate::engine::arena::AstNodeData::BinaryOp { op_id, .. })
631 if data_store.resolve_ast_string(*op_id) == ":" =>
632 {
633 self.interp
634 .with_local_env(env.clone())
635 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry)
636 .ok()
637 }
638 _ => None,
639 },
640 }
641 }
642
643 pub fn inline_array_literal(&self) -> Result<Option<Vec<Vec<LiteralValue>>>, ExcelError> {
644 match &self.expr {
645 ArgumentExpr::Ast(node) => match &node.node_type {
646 ASTNodeType::Literal(LiteralValue::Array(arr)) => Ok(Some(arr.clone())),
647 _ => Ok(None),
648 },
649 ArgumentExpr::Arena {
650 id,
651 data_store,
652 sheet_registry,
653 } => {
654 let node = data_store.get_node(*id).ok_or_else(|| {
655 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
656 })?;
657 match node {
658 crate::engine::arena::AstNodeData::Literal(vref) => {
659 match data_store.retrieve_value(*vref) {
660 LiteralValue::Array(arr) => Ok(Some(arr)),
661 _ => Ok(None),
662 }
663 }
664 _ => {
665 let _ = sheet_registry;
668 Ok(None)
669 }
670 }
671 }
672 }
673 }
674
675 fn local_named_reference(&self, name: &str) -> Option<Result<ReferenceType, ExcelError>> {
694 self.interp.resolve_local_name(name)?;
696 Some(
697 self.interp
698 .resolve_local_bound_reference(name)
699 .ok_or_else(|| {
700 ExcelError::new(ExcelErrorKind::Value)
701 .with_message("LET/LAMBDA local is not a reference")
702 }),
703 )
704 }
705
706 fn reference_for_eval(&self) -> Result<ReferenceType, ExcelError> {
707 match &self.expr {
708 ArgumentExpr::Ast(node) => match &node.node_type {
709 ASTNodeType::Reference { reference, .. } => {
710 if let ReferenceType::NamedRange(name) = reference
713 && let Some(local) = self.local_named_reference(name)
714 {
715 return local;
716 }
717 self.interp.reference_for_current_offset(reference)
718 }
719 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
720 self.interp.evaluate_ast_as_reference(node)
721 }
722 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
723 .with_message("Expected a reference (by-ref argument)")),
724 },
725 ArgumentExpr::Arena {
726 id,
727 data_store,
728 sheet_registry,
729 } => {
730 let node = data_store.get_node(*id).ok_or_else(|| {
731 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
732 })?;
733 match node {
734 crate::engine::arena::AstNodeData::Reference { ref_type, .. } => {
735 if let crate::engine::arena::CompactRefType::NamedRange(name_id) = ref_type
737 && let Some(local) =
738 self.local_named_reference(data_store.resolve_ast_string(*name_id))
739 {
740 return local;
741 }
742 let reference = data_store
743 .reconstruct_reference_type_for_eval(ref_type, sheet_registry);
744 self.interp.reference_for_current_offset(&reference)
745 }
746 crate::engine::arena::AstNodeData::Function { .. }
747 | crate::engine::arena::AstNodeData::BinaryOp { .. } => self
748 .interp
749 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry),
750 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
751 .with_message("Expected a reference (by-ref argument)")),
752 }
753 }
754 }
755 }
756
757 fn function_resolution_attempt(
758 &self,
759 ) -> Option<Result<crate::function::FunctionResolution<'b>, ExcelError>> {
760 match &self.expr {
761 ArgumentExpr::Ast(node) => {
762 let ASTNodeType::Function { name, args } = &node.node_type else {
763 return None;
764 };
765 if !self
766 .interp
767 .context
768 .function_capabilities("", name)
769 .is_some_and(|caps| caps.contains(crate::function::FnCaps::RETURNS_REFERENCE))
770 {
771 return None;
772 }
773 let fun = match self.interp.context.get_function("", name) {
774 Some(fun) => fun,
775 None => {
776 return Some(Err(ExcelError::new(ExcelErrorKind::Name)
777 .with_message(format!("Unknown function: {name}"))));
778 }
779 };
780 let handles: Vec<_> = args
781 .iter()
782 .map(|arg| ArgumentHandle::new(arg, self.interp))
783 .collect();
784 let ctx = DefaultFunctionContext::new_with_sheet(
785 self.interp.context,
786 None,
787 self.interp.current_sheet(),
788 );
789 Some(fun.resolve_reference_or_value(&handles, &ctx, &|| self.value()))
790 }
791 ArgumentExpr::Arena {
792 id,
793 data_store,
794 sheet_registry,
795 } => {
796 let node = match data_store.get_node(*id) {
797 Some(node) => node,
798 None => {
799 return Some(Err(
800 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
801 ));
802 }
803 };
804 let crate::engine::arena::AstNodeData::Function { name_id, .. } = node else {
805 return None;
806 };
807 let name = data_store.resolve_ast_string(*name_id);
808 if !self
809 .interp
810 .context
811 .function_capabilities("", name)
812 .is_some_and(|caps| caps.contains(crate::function::FnCaps::RETURNS_REFERENCE))
813 {
814 return None;
815 }
816 let fun = match self.interp.context.get_function("", name) {
817 Some(fun) => fun,
818 None => {
819 return Some(Err(ExcelError::new(ExcelErrorKind::Name)
820 .with_message(format!("Unknown function: {name}"))));
821 }
822 };
823 let args = match data_store.get_args(*id) {
824 Some(args) => args,
825 None => {
826 return Some(Err(ExcelError::new(ExcelErrorKind::Value)
827 .with_message("Missing function args")));
828 }
829 };
830 let handles: Vec<_> = args
831 .iter()
832 .copied()
833 .map(|arg_id| {
834 ArgumentHandle::new_arena(arg_id, self.interp, data_store, sheet_registry)
835 })
836 .collect();
837 let ctx = DefaultFunctionContext::new_with_sheet(
838 self.interp.context,
839 None,
840 self.interp.current_sheet(),
841 );
842 Some(fun.resolve_reference_or_value(&handles, &ctx, &|| self.value()))
843 }
844 }
845 }
846
847 fn reference_attempt(&self) -> Option<Result<ReferenceType, ExcelError>> {
848 match &self.expr {
849 ArgumentExpr::Ast(node) => match &node.node_type {
850 ASTNodeType::Reference { reference, .. } => {
851 if let ReferenceType::NamedRange(name) = reference
856 && self.interp.resolve_local_name(name).is_some()
857 {
858 return self.interp.resolve_local_bound_reference(name).map(Ok);
859 }
860 Some(self.interp.reference_for_current_offset(reference))
861 }
862 ASTNodeType::BinaryOp { op, .. } if op == ":" => {
863 Some(self.interp.evaluate_ast_as_reference(node))
864 }
865 ASTNodeType::Function { name, .. }
866 if self
867 .interp
868 .context
869 .function_capabilities("", name)
870 .is_some_and(|caps| {
871 caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)
872 }) =>
873 {
874 self.interp.try_evaluate_ast_as_reference(node)
875 }
876 _ => None,
877 },
878 ArgumentExpr::Arena {
879 id,
880 data_store,
881 sheet_registry,
882 } => {
883 let node = match data_store.get_node(*id) {
884 Some(node) => node,
885 None => {
886 return Some(Err(
887 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
888 ));
889 }
890 };
891 match node {
892 crate::engine::arena::AstNodeData::Reference { ref_type, .. } => {
893 if let crate::engine::arena::CompactRefType::NamedRange(name_id) = ref_type
895 {
896 let name = data_store.resolve_ast_string(*name_id);
897 if self.interp.resolve_local_name(name).is_some() {
898 return self.interp.resolve_local_bound_reference(name).map(Ok);
899 }
900 }
901 let reference = data_store
902 .reconstruct_reference_type_for_eval(ref_type, sheet_registry);
903 Some(self.interp.reference_for_current_offset(&reference))
904 }
905 crate::engine::arena::AstNodeData::BinaryOp { op_id, .. }
906 if data_store.resolve_ast_string(*op_id) == ":" =>
907 {
908 Some(self.interp.evaluate_arena_ast_as_reference(
909 *id,
910 data_store,
911 sheet_registry,
912 ))
913 }
914 crate::engine::arena::AstNodeData::Function { name_id, .. } => {
915 let name = data_store.resolve_ast_string(*name_id);
916 if self
917 .interp
918 .context
919 .function_capabilities("", name)
920 .is_some_and(|caps| {
921 caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)
922 })
923 {
924 self.interp.try_evaluate_arena_ast_as_reference(
925 *id,
926 data_store,
927 sheet_registry,
928 )
929 } else {
930 None
931 }
932 }
933 _ => None,
934 }
935 }
936 }
937 }
938
939 pub(crate) fn resolve_reference_or_value(
940 &self,
941 ) -> Result<crate::function::FunctionResolution<'b>, ExcelError> {
942 let resolved = self
943 .cached_reference_or_value
944 .get_or_init(|| self.compute_reference_or_value())
945 .clone();
946 if let Ok(crate::function::FunctionResolution::Value(value)) = &resolved {
947 let _ = self.cached_value.set(Ok(value.clone()));
948 }
949 resolved
950 }
951
952 fn compute_reference_or_value(
953 &self,
954 ) -> Result<crate::function::FunctionResolution<'b>, ExcelError> {
955 if let Some(result) = self.function_resolution_attempt() {
956 return result;
957 }
958 if let Some(reference) = self.reference_attempt() {
959 return Ok(match reference {
960 Ok(reference) => crate::function::FunctionResolution::Reference(reference),
961 Err(error) => crate::function::FunctionResolution::ReferenceError(error),
962 });
963 }
964 self.value().map(crate::function::FunctionResolution::Value)
965 }
966
967 pub(crate) fn resolve_once(&self) -> Result<ResolvedArgument<'b>, ExcelError> {
973 self.cached_resolved
974 .get_or_init(|| self.compute_resolved_argument())
975 .clone()
976 }
977
978 pub(crate) fn with_context_cancel_token(&self, view: RangeView<'b>) -> RangeView<'b> {
979 match self.interp.context.cancellation_token() {
980 Some(token) => view.with_cancel_token(Some(token)),
981 None => view,
982 }
983 }
984
985 fn compute_resolved_argument(&self) -> Result<ResolvedArgument<'b>, ExcelError> {
986 let value = match self.resolve_reference_or_value()? {
987 crate::function::FunctionResolution::Reference(reference) => {
988 return match self
989 .interp
990 .context
991 .resolve_range_view(&reference, self.interp.current_sheet())
992 {
993 Ok(view) => Ok(ResolvedArgument::Range(
994 self.with_context_cancel_token(view),
995 )),
996 Err(error) if error.kind == ExcelErrorKind::Cancelled => Err(error),
997 Err(error) => Ok(ResolvedArgument::ReferenceError(error)),
998 };
999 }
1000 crate::function::FunctionResolution::ReferenceError(error)
1001 if error.kind == ExcelErrorKind::Cancelled =>
1002 {
1003 return Err(error);
1004 }
1005 crate::function::FunctionResolution::ReferenceError(error) => {
1006 return Ok(ResolvedArgument::ReferenceError(error));
1007 }
1008 crate::function::FunctionResolution::Value(value) => value,
1009 };
1010
1011 match value {
1012 CalcValue::Range(view) => Ok(ResolvedArgument::Range(
1013 self.with_context_cancel_token(view),
1014 )),
1015 CalcValue::Scalar(LiteralValue::Array(rows)) => {
1016 let view = RangeView::try_from_owned_rows(
1017 rows,
1018 self.interp.context.date_system(),
1019 self.interp.context.cancellation_token(),
1020 )?;
1021 Ok(ResolvedArgument::Range(view))
1022 }
1023 other => Ok(ResolvedArgument::Value(other)),
1024 }
1025 }
1026
1027 pub fn range(&self) -> Result<Box<dyn Range>, ExcelError> {
1028 match &self.expr {
1029 ArgumentExpr::Ast(node) => match &node.node_type {
1030 ASTNodeType::Reference { reference, .. } => {
1031 let reference = self.interp.reference_for_current_offset(reference)?;
1033 let view = self
1034 .interp
1035 .context
1036 .resolve_range_view(&reference, self.interp.current_sheet())?;
1037 let (rows, cols) = view.dims();
1038 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
1039 view.for_each_row(&mut |row| {
1040 let row_data: Vec<LiteralValue> = (0..cols)
1041 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
1042 .collect();
1043 out.push(row_data);
1044 Ok(())
1045 })?;
1046 Ok(Box::new(InMemoryRange::new(out)))
1047 }
1048 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
1049 let reference = self.reference_for_eval()?;
1050 let view = self
1051 .interp
1052 .context
1053 .resolve_range_view(&reference, self.interp.current_sheet())?;
1054 let (rows, cols) = view.dims();
1055 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
1056 view.for_each_row(&mut |row| {
1057 let row_data: Vec<LiteralValue> = (0..cols)
1058 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
1059 .collect();
1060 out.push(row_data);
1061 Ok(())
1062 })?;
1063 Ok(Box::new(InMemoryRange::new(out)))
1064 }
1065 ASTNodeType::Array(rows) => {
1066 let mut materialized = Vec::new();
1067 for row in rows {
1068 let mut materialized_row = Vec::new();
1069 for cell in row {
1070 materialized_row.push(self.interp.evaluate_ast(cell)?.into_literal());
1071 }
1072 materialized.push(materialized_row);
1073 }
1074 Ok(Box::new(InMemoryRange::new(materialized)))
1075 }
1076 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1077 .with_message(format!("Expected a range, got {:?}", node.node_type))),
1078 },
1079 ArgumentExpr::Arena { id, data_store, .. } => {
1080 let node = data_store.get_node(*id).ok_or_else(|| {
1081 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
1082 })?;
1083
1084 match node {
1085 crate::engine::arena::AstNodeData::Reference { .. }
1086 | crate::engine::arena::AstNodeData::Function { .. }
1087 | crate::engine::arena::AstNodeData::BinaryOp { .. } => {
1088 let reference = self.reference_for_eval()?;
1089 let view = self
1090 .interp
1091 .context
1092 .resolve_range_view(&reference, self.interp.current_sheet())?;
1093 let (rows, cols) = view.dims();
1094 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
1095 view.for_each_row(&mut |row| {
1096 let row_data: Vec<LiteralValue> = (0..cols)
1097 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
1098 .collect();
1099 out.push(row_data);
1100 Ok(())
1101 })?;
1102 Ok(Box::new(InMemoryRange::new(out)))
1103 }
1104 crate::engine::arena::AstNodeData::Array { .. } => {
1105 let (rows, cols, elements) =
1106 data_store.get_array_elems(*id).ok_or_else(|| {
1107 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
1108 })?;
1109 let rows_usize = rows as usize;
1110 let cols_usize = cols as usize;
1111 let mut materialized: Vec<Vec<LiteralValue>> =
1112 Vec::with_capacity(rows_usize);
1113 for r in 0..rows_usize {
1114 let mut row = Vec::with_capacity(cols_usize);
1115 for c in 0..cols_usize {
1116 let idx = r * cols_usize + c;
1117 let elem_id = elements.get(idx).copied().ok_or_else(|| {
1118 ExcelError::new(ExcelErrorKind::Value)
1119 .with_message("Invalid array")
1120 })?;
1121 let v = self.interp.evaluate_arena_ast(
1122 elem_id,
1123 data_store,
1124 self.sheet_registry(),
1125 )?;
1126 row.push(v.into_literal());
1127 }
1128 materialized.push(row);
1129 }
1130 Ok(Box::new(InMemoryRange::new(materialized)))
1131 }
1132 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1133 .with_message("Argument cannot be interpreted as a range.")),
1134 }
1135 }
1136 }
1137 }
1138
1139 fn sheet_registry(&self) -> &crate::engine::sheet_registry::SheetRegistry {
1140 match &self.expr {
1141 ArgumentExpr::Ast(_) => {
1142 unreachable!("sheet_registry only used for arena ArgumentHandle")
1144 }
1145 ArgumentExpr::Arena { sheet_registry, .. } => sheet_registry,
1146 }
1147 }
1148
1149 pub fn range_view(&self) -> Result<RangeView<'b>, ExcelError> {
1157 match self.resolve_once()? {
1158 ResolvedArgument::Range(view) => Ok(view),
1159 ResolvedArgument::ReferenceError(error) => Err(error),
1162 ResolvedArgument::Value(CalcValue::Range(view)) => {
1167 Ok(self.with_context_cancel_token(view))
1168 }
1169 ResolvedArgument::Value(CalcValue::Scalar(LiteralValue::Array(rows))) => {
1170 RangeView::try_from_owned_rows(
1171 rows,
1172 self.interp.context.date_system(),
1173 self.interp.context.cancellation_token(),
1174 )
1175 }
1176 ResolvedArgument::Value(_) => Err(ExcelError::new(ExcelErrorKind::Ref)
1177 .with_message("Argument cannot be interpreted as a range.")),
1178 }
1179 }
1180
1181 pub fn range_view_or_scalar(&self) -> Result<RangeView<'b>, ExcelError> {
1201 match self.resolve_once()? {
1202 ResolvedArgument::Range(view) => Ok(view),
1203 ResolvedArgument::ReferenceError(error) => Err(error),
1204 ResolvedArgument::Value(CalcValue::Range(view)) => {
1205 Ok(self.with_context_cancel_token(view))
1206 }
1207 ResolvedArgument::Value(CalcValue::Scalar(LiteralValue::Array(rows))) => {
1208 RangeView::try_from_owned_rows(
1209 rows,
1210 self.interp.context.date_system(),
1211 self.interp.context.cancellation_token(),
1212 )
1213 }
1214 ResolvedArgument::Value(CalcValue::Scalar(LiteralValue::Error(error))) => Err(error),
1217 ResolvedArgument::Value(
1218 CalcValue::Scalar(scalar) | CalcValue::AnnotatedScalar(scalar, _),
1219 ) => RangeView::try_from_owned_rows(
1220 vec![vec![scalar]],
1221 self.interp.context.date_system(),
1222 self.interp.context.cancellation_token(),
1223 ),
1224 ResolvedArgument::Value(CalcValue::Callable(_)) => {
1226 Err(ExcelError::new(ExcelErrorKind::Ref)
1227 .with_message("Argument cannot be interpreted as a range."))
1228 }
1229 }
1230 }
1231
1232 pub fn value_or_range(&self) -> Result<EvaluatedArg<'_>, ExcelError> {
1233 self.range().map(EvaluatedArg::Range).or_else(|_| {
1234 self.value()
1235 .map(|cv| EvaluatedArg::LiteralValue(Cow::Owned(cv.into_literal())))
1236 })
1237 }
1238
1239 pub fn lazy_values_owned(
1244 &'a self,
1245 ) -> Result<Box<dyn Iterator<Item = LiteralValue> + 'a>, ExcelError> {
1246 fn resolved_values<'a, 'b>(
1250 handle: &'a ArgumentHandle<'a, 'b>,
1251 ) -> Result<Box<dyn Iterator<Item = LiteralValue> + 'a>, ExcelError> {
1252 match handle.resolve_once()? {
1253 ResolvedArgument::Range(view) => {
1254 let mut values = Vec::new();
1255 view.for_each_cell(&mut |value| {
1256 values.push(value.clone());
1257 Ok(())
1258 })?;
1259 Ok(Box::new(values.into_iter()))
1260 }
1261 ResolvedArgument::ReferenceError(error) => Err(error),
1262 ResolvedArgument::Value(value) => {
1263 Ok(Box::new(std::iter::once(value.into_literal())))
1264 }
1265 }
1266 }
1267
1268 match &self.expr {
1269 ArgumentExpr::Ast(node) => match &node.node_type {
1270 ASTNodeType::Reference { .. } => resolved_values(self),
1271 ASTNodeType::Array(rows) => {
1272 struct ArrayEvalIter<'a, 'b> {
1273 rows: &'a [Vec<ASTNode>],
1274 r: usize,
1275 c: usize,
1276 interp: &'a Interpreter<'b>,
1277 }
1278 impl<'a, 'b> Iterator for ArrayEvalIter<'a, 'b> {
1279 type Item = LiteralValue;
1280 fn next(&mut self) -> Option<Self::Item> {
1281 if self.rows.is_empty() {
1282 return None;
1283 }
1284 let rows = self.rows;
1285 let mut r = self.r;
1286 let mut c = self.c;
1287 if r >= rows.len() {
1288 return None;
1289 }
1290 let node = &rows[r][c];
1291 c += 1;
1293 if c >= rows[r].len() {
1294 r += 1;
1295 c = 0;
1296 }
1297 self.r = r;
1298 self.c = c;
1299 match self.interp.evaluate_ast(node) {
1300 Ok(cv) => Some(cv.into_literal()),
1301 Err(e) => Some(LiteralValue::Error(e)),
1302 }
1303 }
1304 }
1305 let it = ArrayEvalIter {
1306 rows,
1307 r: 0,
1308 c: 0,
1309 interp: self.interp,
1310 };
1311 Ok(Box::new(it))
1312 }
1313 _ => {
1314 let v = self.value()?.into_literal();
1316 Ok(Box::new(std::iter::once(v)))
1317 }
1318 },
1319 ArgumentExpr::Arena {
1320 id,
1321 data_store,
1322 sheet_registry,
1323 } => {
1324 let node = data_store.get_node(*id).ok_or_else(|| {
1325 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
1326 })?;
1327
1328 match node {
1329 crate::engine::arena::AstNodeData::Reference { .. } => resolved_values(self),
1330 crate::engine::arena::AstNodeData::Array { .. } => {
1331 let (rows, cols, elements) =
1332 data_store.get_array_elems(*id).ok_or_else(|| {
1333 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
1334 })?;
1335
1336 struct ArenaArrayEvalIter<'a, 'b> {
1337 elements: &'a [crate::engine::arena::AstNodeId],
1338 idx: usize,
1339 interp: &'a Interpreter<'b>,
1340 data_store: &'a crate::engine::arena::DataStore,
1341 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
1342 }
1343
1344 impl<'a, 'b> Iterator for ArenaArrayEvalIter<'a, 'b> {
1345 type Item = LiteralValue;
1346
1347 fn next(&mut self) -> Option<Self::Item> {
1348 let id = self.elements.get(self.idx).copied()?;
1349 self.idx += 1;
1350 match self.interp.evaluate_arena_ast(
1351 id,
1352 self.data_store,
1353 self.sheet_registry,
1354 ) {
1355 Ok(cv) => Some(cv.into_literal()),
1356 Err(e) => Some(LiteralValue::Error(e)),
1357 }
1358 }
1359 }
1360
1361 let _ = (rows, cols);
1362 let it = ArenaArrayEvalIter {
1363 elements,
1364 idx: 0,
1365 interp: self.interp,
1366 data_store,
1367 sheet_registry,
1368 };
1369 Ok(Box::new(it))
1370 }
1371 _ => {
1372 let v = self
1373 .interp
1374 .evaluate_arena_ast(*id, data_store, sheet_registry)?;
1375 Ok(Box::new(std::iter::once(v.into_literal())))
1376 }
1377 }
1378 }
1379 }
1380 }
1381
1382 pub fn ast(&self) -> &ASTNode {
1383 match &self.expr {
1384 ArgumentExpr::Ast(node) => node,
1385 ArgumentExpr::Arena {
1386 id,
1387 data_store,
1388 sheet_registry,
1389 } => self.cached_ast.get_or_init(|| {
1390 data_store
1391 .retrieve_ast(*id, sheet_registry)
1392 .unwrap_or_else(|| ASTNode {
1393 node_type: ASTNodeType::Literal(LiteralValue::Error(
1394 ExcelError::new(ExcelErrorKind::Value)
1395 .with_message("Missing formula AST"),
1396 )),
1397 source_token: None,
1398 contains_volatile: false,
1399 })
1400 }),
1401 }
1402 }
1403
1404 pub fn as_reference(&self) -> Result<&ReferenceType, ExcelError> {
1407 match &self.expr {
1408 ArgumentExpr::Ast(node) => match &node.node_type {
1409 ASTNodeType::Reference { reference, .. } => {
1410 if let ReferenceType::NamedRange(name) = reference
1412 && let Some(local) = self.local_named_reference(name)
1413 {
1414 let bound = local?;
1415 return Ok(self.cached_ref.get_or_init(|| bound));
1416 }
1417 Ok(reference)
1418 }
1419 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1420 .with_message("Expected a reference (by-ref argument)")),
1421 },
1422 ArgumentExpr::Arena { .. } => {
1423 let reference = self.reference_for_eval()?;
1424 Ok(self.cached_ref.get_or_init(|| reference))
1425 }
1426 }
1427 }
1428
1429 pub fn as_reference_or_eval(&self) -> Result<ReferenceType, ExcelError> {
1432 match &self.expr {
1433 ArgumentExpr::Ast(node) => match &node.node_type {
1434 ASTNodeType::Reference { reference, .. } => {
1435 if let ReferenceType::NamedRange(name) = reference
1437 && let Some(local) = self.local_named_reference(name)
1438 {
1439 return local;
1440 }
1441 self.interp.reference_for_current_offset(reference)
1442 }
1443 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
1444 self.interp.evaluate_ast_as_reference(node)
1445 }
1446 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1447 .with_message("Argument is not a reference")),
1448 },
1449 ArgumentExpr::Arena {
1450 id,
1451 data_store,
1452 sheet_registry,
1453 } => {
1454 let node = data_store.get_node(*id).ok_or_else(|| {
1455 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
1456 })?;
1457
1458 match node {
1459 crate::engine::arena::AstNodeData::Reference { .. } => {
1460 self.reference_for_eval()
1461 }
1462 crate::engine::arena::AstNodeData::Function { .. }
1463 | crate::engine::arena::AstNodeData::BinaryOp { .. } => self
1464 .interp
1465 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry),
1466 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1467 .with_message("Argument is not a reference")),
1468 }
1469 }
1470 }
1471 }
1472
1473 pub fn matches_kind(&self, k: formualizer_common::ArgKind) -> Result<bool, ExcelError> {
1475 Ok(match k {
1476 formualizer_common::ArgKind::Any => true,
1477 formualizer_common::ArgKind::Range => self.range().is_ok(),
1478 formualizer_common::ArgKind::Number => matches!(
1479 self.value()?.into_literal(),
1480 LiteralValue::Number(_) | LiteralValue::Int(_)
1481 ),
1482 formualizer_common::ArgKind::Text => {
1483 matches!(self.value()?.into_literal(), LiteralValue::Text(_))
1484 }
1485 formualizer_common::ArgKind::Logical => {
1486 matches!(self.value()?.into_literal(), LiteralValue::Boolean(_))
1487 }
1488 })
1489 }
1490}
1491
1492#[derive(Debug, Clone)]
1494pub struct InMemoryRange {
1495 data: Vec<Vec<LiteralValue>>,
1496}
1497impl InMemoryRange {
1498 pub fn new(d: Vec<Vec<LiteralValue>>) -> Self {
1499 Self { data: d }
1500 }
1501}
1502impl Range for InMemoryRange {
1503 fn get(&self, r: usize, c: usize) -> Result<LiteralValue, ExcelError> {
1504 Ok(self
1505 .data
1506 .get(r)
1507 .and_then(|row| row.get(c))
1508 .cloned()
1509 .unwrap_or(LiteralValue::Empty))
1510 }
1511 fn dimensions(&self) -> (usize, usize) {
1512 (self.data.len(), self.data.first().map_or(0, |r| r.len()))
1513 }
1514 fn as_any(&self) -> &dyn Any {
1515 self
1516 }
1517}
1518
1519pub trait Table: Debug + Send + Sync {
1522 fn get_cell(&self, row: usize, column: &str) -> Result<LiteralValue, ExcelError>;
1523 fn get_column(&self, column: &str) -> Result<Box<dyn Range>, ExcelError>;
1524 fn columns(&self) -> Vec<String> {
1526 vec![]
1527 }
1528 fn data_height(&self) -> usize {
1530 0
1531 }
1532 fn has_headers(&self) -> bool {
1534 false
1535 }
1536 fn has_totals(&self) -> bool {
1538 false
1539 }
1540 fn headers_row(&self) -> Option<Box<dyn Range>> {
1542 None
1543 }
1544 fn totals_row(&self) -> Option<Box<dyn Range>> {
1546 None
1547 }
1548 fn data_body(&self) -> Option<Box<dyn Range>> {
1550 None
1551 }
1552 fn clone_box(&self) -> Box<dyn Table>;
1553}
1554impl Table for Box<dyn Table> {
1555 fn get_cell(&self, r: usize, c: &str) -> Result<LiteralValue, ExcelError> {
1556 (**self).get_cell(r, c)
1557 }
1558 fn get_column(&self, c: &str) -> Result<Box<dyn Range>, ExcelError> {
1559 (**self).get_column(c)
1560 }
1561 fn columns(&self) -> Vec<String> {
1562 (**self).columns()
1563 }
1564 fn data_height(&self) -> usize {
1565 (**self).data_height()
1566 }
1567 fn has_headers(&self) -> bool {
1568 (**self).has_headers()
1569 }
1570 fn has_totals(&self) -> bool {
1571 (**self).has_totals()
1572 }
1573 fn headers_row(&self) -> Option<Box<dyn Range>> {
1574 (**self).headers_row()
1575 }
1576 fn totals_row(&self) -> Option<Box<dyn Range>> {
1577 (**self).totals_row()
1578 }
1579 fn data_body(&self) -> Option<Box<dyn Range>> {
1580 (**self).data_body()
1581 }
1582 fn clone_box(&self) -> Box<dyn Table> {
1583 (**self).clone_box()
1584 }
1585}
1586
1587pub trait ReferenceResolver: Send + Sync {
1590 fn resolve_cell_reference(
1591 &self,
1592 sheet: Option<&str>,
1593 row: u32,
1594 col: u32,
1595 ) -> Result<LiteralValue, ExcelError>;
1596}
1597pub trait RangeResolver: Send + Sync {
1598 fn resolve_range_reference(
1599 &self,
1600 sheet: Option<&str>,
1601 sr: Option<u32>,
1602 sc: Option<u32>,
1603 er: Option<u32>,
1604 ec: Option<u32>,
1605 ) -> Result<Box<dyn Range>, ExcelError>;
1606}
1607pub trait NamedRangeResolver: Send + Sync {
1608 fn resolve_named_range_reference(
1609 &self,
1610 name: &str,
1611 ) -> Result<Vec<Vec<LiteralValue>>, ExcelError>;
1612}
1613pub trait TableResolver: Send + Sync {
1614 fn resolve_table_reference(
1615 &self,
1616 tref: &formualizer_parse::parser::TableReference,
1617 ) -> Result<Box<dyn Table>, ExcelError>;
1618}
1619
1620pub trait SourceResolver: Send + Sync {
1621 fn source_scalar_version(&self, _name: &str) -> Option<u64> {
1622 None
1623 }
1624
1625 fn resolve_source_scalar(&self, name: &str) -> Result<LiteralValue, ExcelError> {
1626 Err(ExcelError::new(ExcelErrorKind::NImpl)
1627 .with_message(format!("Source scalar not supported: {name}")))
1628 }
1629
1630 fn source_table_version(&self, _name: &str) -> Option<u64> {
1631 None
1632 }
1633
1634 fn resolve_source_table(&self, name: &str) -> Result<Box<dyn Table>, ExcelError> {
1635 Err(ExcelError::new(ExcelErrorKind::NImpl)
1636 .with_message(format!("Source table not supported: {name}")))
1637 }
1638}
1639
1640pub trait Resolver: ReferenceResolver + RangeResolver + NamedRangeResolver + TableResolver {
1641 fn resolve_range_like(&self, r: &ReferenceType) -> Result<Box<dyn Range>, ExcelError> {
1642 match r {
1643 ReferenceType::Range {
1644 sheet,
1645 start_row,
1646 start_col,
1647 end_row,
1648 end_col,
1649 ..
1650 } => self.resolve_range_reference(
1651 sheet.as_deref(),
1652 *start_row,
1653 *start_col,
1654 *end_row,
1655 *end_col,
1656 ),
1657 ReferenceType::External(_) => Err(ExcelError::new(ExcelErrorKind::NImpl)
1658 .with_message("External references are not supported by Resolver".to_string())),
1659 ReferenceType::Table(tref) => {
1660 let t = self.resolve_table_reference(tref)?;
1661 match &tref.specifier {
1662 Some(TableSpecifier::Column(c)) => t.get_column(c),
1663 Some(TableSpecifier::ColumnRange(start, end)) => {
1664 let cols = t.columns();
1666 let start_key = start.to_lowercase();
1667 let end_key = end.to_lowercase();
1668 let start_idx = cols.iter().position(|n| n.to_lowercase() == start_key);
1669 let end_idx = cols.iter().position(|n| n.to_lowercase() == end_key);
1670 if let (Some(mut si), Some(mut ei)) = (start_idx, end_idx) {
1671 if si > ei {
1672 std::mem::swap(&mut si, &mut ei);
1673 }
1674 let h = t.data_height();
1676 let w = ei - si + 1;
1677 let mut rows = vec![vec![LiteralValue::Empty; w]; h];
1678 for (offset, ci) in (si..=ei).enumerate() {
1679 let cname = &cols[ci];
1680 let col_range = t.get_column(cname)?;
1681 let (rh, _) = col_range.dimensions();
1682 for (r, row) in rows.iter_mut().enumerate().take(h.min(rh)) {
1683 row[offset] = col_range.get(r, 0)?;
1684 }
1685 }
1686 Ok(Box::new(InMemoryRange::new(rows)))
1687 } else {
1688 Err(ExcelError::new(ExcelErrorKind::Ref).with_message(
1689 "Column range refers to unknown column(s)".to_string(),
1690 ))
1691 }
1692 }
1693 Some(TableSpecifier::SpecialItem(
1694 formualizer_parse::parser::SpecialItem::Headers,
1695 )) => {
1696 if let Some(h) = t.headers_row() {
1697 Ok(h)
1698 } else {
1699 Ok(Box::new(InMemoryRange::new(vec![])))
1700 }
1701 }
1702 Some(TableSpecifier::SpecialItem(
1703 formualizer_parse::parser::SpecialItem::Totals,
1704 )) => {
1705 if let Some(tr) = t.totals_row() {
1706 Ok(tr)
1707 } else {
1708 Ok(Box::new(InMemoryRange::new(vec![])))
1709 }
1710 }
1711 Some(TableSpecifier::SpecialItem(
1712 formualizer_parse::parser::SpecialItem::Data,
1713 )) => {
1714 if let Some(body) = t.data_body() {
1715 Ok(body)
1716 } else {
1717 Ok(Box::new(InMemoryRange::new(vec![])))
1718 }
1719 }
1720 Some(TableSpecifier::SpecialItem(
1721 formualizer_parse::parser::SpecialItem::All,
1722 )) => {
1723 let mut out: Vec<Vec<LiteralValue>> = Vec::new();
1725 if let Some(h) = t.headers_row() {
1726 out.extend(h.iter_rows());
1727 }
1728 if let Some(body) = t.data_body() {
1729 out.extend(body.iter_rows());
1730 }
1731 if let Some(tr) = t.totals_row() {
1732 out.extend(tr.iter_rows());
1733 }
1734 Ok(Box::new(InMemoryRange::new(out)))
1735 }
1736 Some(TableSpecifier::SpecialItem(
1737 formualizer_parse::parser::SpecialItem::ThisRow,
1738 )) => Err(ExcelError::new(ExcelErrorKind::NImpl).with_message(
1739 "@ (This Row) requires table-aware context; not yet supported".to_string(),
1740 )),
1741 Some(TableSpecifier::All) => {
1742 let mut out: Vec<Vec<LiteralValue>> = Vec::new();
1744 if let Some(h) = t.headers_row() {
1745 out.extend(h.iter_rows());
1746 }
1747 if let Some(body) = t.data_body() {
1748 out.extend(body.iter_rows());
1749 }
1750 if let Some(tr) = t.totals_row() {
1751 out.extend(tr.iter_rows());
1752 }
1753 Ok(Box::new(InMemoryRange::new(out)))
1754 }
1755 Some(TableSpecifier::Data) => {
1756 if let Some(body) = t.data_body() {
1757 Ok(body)
1758 } else {
1759 Ok(Box::new(InMemoryRange::new(vec![])))
1760 }
1761 }
1762 Some(TableSpecifier::Combination(_)) => Err(ExcelError::new(
1764 ExcelErrorKind::NImpl,
1765 )
1766 .with_message("Complex structured references not yet supported".to_string())),
1767 Some(TableSpecifier::Row(_)) => Err(ExcelError::new(ExcelErrorKind::NImpl)
1768 .with_message("Row selectors (@/index) not yet supported".to_string())),
1769 Some(TableSpecifier::Headers) | Some(TableSpecifier::Totals) => {
1770 Err(ExcelError::new(ExcelErrorKind::NImpl).with_message(
1771 "Legacy Headers/Totals variants not used; use SpecialItem".to_string(),
1772 ))
1773 }
1774 None => Err(ExcelError::new(ExcelErrorKind::Ref).with_message(
1775 "Table reference without specifier is unsupported".to_string(),
1776 )),
1777 }
1778 }
1779 ReferenceType::NamedRange(n) => {
1780 let v = self.resolve_named_range_reference(n)?;
1781 Ok(Box::new(InMemoryRange::new(v)))
1782 }
1783 ReferenceType::Cell {
1784 sheet, row, col, ..
1785 } => {
1786 let v = self.resolve_cell_reference(sheet.as_deref(), *row, *col)?;
1787 Ok(Box::new(InMemoryRange::new(vec![vec![v]])))
1788 }
1789 ReferenceType::Cell3D { .. } | ReferenceType::Range3D { .. } => {
1790 Err(ExcelError::new(ExcelErrorKind::NImpl)
1791 .with_message("3D references are not yet supported".to_string()))
1792 }
1793 }
1794 }
1795}
1796
1797pub trait FunctionProvider: Send + Sync {
1800 fn get_function(&self, ns: &str, name: &str) -> Option<Arc<dyn Function>>;
1801
1802 #[doc(hidden)]
1803 fn get_function_for_planning(&self, _ns: &str, _name: &str) -> Option<Arc<dyn Function>> {
1804 None
1805 }
1806
1807 #[doc(hidden)]
1810 fn planning_semantic_revision(&self) -> Option<u64> {
1811 None
1812 }
1813
1814 #[doc(hidden)]
1815 fn function_capabilities(&self, ns: &str, name: &str) -> Option<crate::function::FnCaps> {
1816 self.get_function(ns, name).map(|function| function.caps())
1817 }
1818
1819 fn function_semantic_identity(
1820 &self,
1821 ns: &str,
1822 name: &str,
1823 arity: usize,
1824 ) -> Option<crate::function_contract::FunctionSemanticIdentity> {
1825 crate::function_registry::resolve_semantic_identity(self, ns, name, arity)
1826 }
1827}
1828
1829pub trait EvaluationContext: Resolver + FunctionProvider + SourceResolver {
1830 fn thread_pool(&self) -> Option<&Arc<rayon::ThreadPool>> {
1833 None
1834 }
1835
1836 fn cancellation_token(&self) -> Option<crate::engine::CancelToken> {
1843 None
1844 }
1845
1846 fn chunk_hint(&self) -> Option<usize> {
1848 None
1849 }
1850
1851 fn resolve_range_view<'c>(
1854 &'c self,
1855 _reference: &ReferenceType,
1856 _current_sheet: &str,
1857 ) -> Result<RangeView<'c>, ExcelError> {
1858 Err(ExcelError::new(ExcelErrorKind::NImpl))
1859 }
1860
1861 fn resolve_cell_reference_value(
1866 &self,
1867 sheet: Option<&str>,
1868 row: u32,
1869 col: u32,
1870 current_sheet: &str,
1871 ) -> Result<LiteralValue, ExcelError> {
1872 let reference = ReferenceType::Cell {
1873 sheet: sheet.map(str::to_string),
1874 row,
1875 col,
1876 row_abs: true,
1877 col_abs: true,
1878 };
1879 let view = self.resolve_range_view(&reference, current_sheet)?;
1880 Ok(view.as_1x1().unwrap_or(LiteralValue::Empty))
1881 }
1882
1883 fn resolve_cell_format(
1885 &self,
1886 _sheet: Option<&str>,
1887 _row: u32,
1888 _col: u32,
1889 _current_sheet: &str,
1890 ) -> Option<crate::format::FormatId> {
1891 None
1892 }
1893
1894 #[doc(hidden)]
1899 fn resolve_cell_reference_value_formatted(
1900 &self,
1901 sheet: Option<&str>,
1902 row: u32,
1903 col: u32,
1904 current_sheet: &str,
1905 ) -> Result<(LiteralValue, Option<crate::format::FormatId>), ExcelError> {
1906 let value = self.resolve_cell_reference_value(sheet, row, col, current_sheet)?;
1907 Ok((
1908 value,
1909 self.resolve_cell_format(sheet, row, col, current_sheet),
1910 ))
1911 }
1912
1913 fn format_class(
1915 &self,
1916 format: crate::format::FormatId,
1917 ) -> Option<formualizer_common::numfmt::FormatClass> {
1918 formualizer_common::numfmt::NumberFormat::builtin(format.0)
1919 .map(|format| format.class().clone())
1920 }
1921
1922 fn record_cell_derived_format(
1924 &self,
1925 _sheet: &str,
1926 _row: u32,
1927 _col: u32,
1928 _format: Option<crate::format::FormatId>,
1929 ) {
1930 }
1931
1932 fn locale(&self) -> crate::locale::Locale {
1934 crate::locale::Locale::invariant()
1935 }
1936
1937 fn workbook_sheet_count(&self) -> Option<usize> {
1939 None
1940 }
1941
1942 fn sheet_index_by_name(&self, _sheet: &str) -> Option<usize> {
1944 None
1945 }
1946
1947 fn current_sheet_index(&self, current_sheet: &str) -> Option<usize> {
1949 self.sheet_index_by_name(current_sheet)
1950 }
1951
1952 fn inspect_reference(
1954 &self,
1955 _reference: &ReferenceType,
1956 _current_sheet: &str,
1957 ) -> Result<Option<ReferenceInfo>, ExcelError> {
1958 Ok(None)
1959 }
1960
1961 fn formula_text_at_cell(&self, _cell: CellRef) -> Result<Option<String>, ExcelError> {
1963 Ok(None)
1964 }
1965
1966 fn clock(&self) -> &dyn crate::timezone::ClockProvider {
1975 #[cfg(feature = "system-clock")]
1976 {
1977 static DEFAULT_CLOCK: std::sync::OnceLock<crate::timezone::SystemClock> =
1978 std::sync::OnceLock::new();
1979 DEFAULT_CLOCK.get_or_init(|| {
1980 crate::timezone::SystemClock::new(crate::timezone::TimeZoneSpec::default())
1981 })
1982 }
1983 #[cfg(not(feature = "system-clock"))]
1984 {
1985 static DEFAULT_CLOCK: std::sync::OnceLock<crate::timezone::FixedClock> =
1986 std::sync::OnceLock::new();
1987 DEFAULT_CLOCK.get_or_init(|| {
1988 crate::timezone::FixedClock::new(
1989 chrono::DateTime::UNIX_EPOCH,
1990 crate::timezone::TimeZoneSpec::Utc,
1991 )
1992 })
1993 }
1994 }
1995
1996 fn timezone(&self) -> &crate::timezone::TimeZoneSpec {
2000 self.clock().timezone()
2001 }
2002
2003 fn volatile_level(&self) -> VolatileLevel {
2005 VolatileLevel::Always
2006 }
2007
2008 fn workbook_seed(&self) -> u64 {
2010 0xF0F0_D0D0_AAAA_5555
2011 }
2012
2013 fn recalc_epoch(&self) -> u64 {
2015 0
2016 }
2017
2018 fn used_rows_for_columns(
2023 &self,
2024 _sheet: &str,
2025 _start_col: u32,
2026 _end_col: u32,
2027 ) -> Option<(u32, u32)> {
2028 None
2029 }
2030
2031 fn used_cols_for_rows(
2034 &self,
2035 _sheet: &str,
2036 _start_row: u32,
2037 _end_row: u32,
2038 ) -> Option<(u32, u32)> {
2039 None
2040 }
2041
2042 fn sheet_bounds(&self, _sheet: &str) -> Option<(u32, u32)> {
2044 None
2045 }
2046
2047 fn data_snapshot_id(&self) -> u64 {
2049 0
2050 }
2051
2052 fn backend_caps(&self) -> BackendCaps {
2054 BackendCaps::default()
2055 }
2056
2057 fn date_system(&self) -> crate::engine::DateSystem {
2062 crate::engine::DateSystem::Excel1900
2063 }
2064
2065 fn build_lookup_index(
2068 &self,
2069 _view: &RangeView<'_>,
2070 _axis: LookupAxis,
2071 ) -> Option<std::sync::Arc<LookupIndex>> {
2072 None
2073 }
2074
2075 fn build_criteria_mask(
2078 &self,
2079 _view: &RangeView<'_>,
2080 _col_in_view: usize,
2081 _pred: &crate::args::CriteriaPredicate,
2082 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2083 None
2084 }
2085
2086 fn build_row_visibility_mask(
2089 &self,
2090 _view: &RangeView<'_>,
2091 _mode: VisibilityMaskMode,
2092 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2093 None
2094 }
2095}
2096
2097#[derive(Copy, Clone, Debug, Default)]
2099pub struct BackendCaps {
2100 pub streaming: bool,
2102 pub used_region: bool,
2104 pub write: bool,
2106 pub tables: bool,
2108 pub async_stream: bool,
2110}
2111
2112#[derive(Copy, Clone, Debug, Eq, PartialEq)]
2115pub enum VolatileLevel {
2116 Always,
2118 OnRecalc,
2120 OnOpen,
2122}
2123
2124pub trait FunctionContext<'ctx> {
2126 fn locale(&self) -> crate::locale::Locale;
2127 fn timezone(&self) -> &crate::timezone::TimeZoneSpec;
2128 fn clock(&self) -> &dyn crate::timezone::ClockProvider;
2129 fn thread_pool(&self) -> Option<&std::sync::Arc<rayon::ThreadPool>>;
2130 fn cancellation_token(&self) -> Option<crate::engine::CancelToken>;
2136 fn chunk_hint(&self) -> Option<usize>;
2137
2138 fn current_sheet(&self) -> &str;
2140
2141 fn workbook_sheet_count(&self) -> Option<usize> {
2142 None
2143 }
2144
2145 fn sheet_index_by_name(&self, _sheet: &str) -> Option<usize> {
2146 None
2147 }
2148
2149 fn current_sheet_index(&self) -> Option<usize> {
2150 self.sheet_index_by_name(self.current_sheet())
2151 }
2152
2153 fn inspect_reference(
2154 &self,
2155 _reference: &ReferenceType,
2156 ) -> Result<Option<ReferenceInfo>, ExcelError> {
2157 Ok(None)
2158 }
2159
2160 fn formula_text_at_cell(&self, _cell: CellRef) -> Result<Option<String>, ExcelError> {
2161 Ok(None)
2162 }
2163
2164 fn volatile_level(&self) -> VolatileLevel;
2165 fn workbook_seed(&self) -> u64;
2166 fn recalc_epoch(&self) -> u64;
2167 fn current_cell(&self) -> Option<CellRef>;
2168
2169 fn resolve_range_view(
2171 &self,
2172 _reference: &ReferenceType,
2173 _current_sheet: &str,
2174 ) -> Result<RangeView<'ctx>, ExcelError>;
2175
2176 fn rng_for_current(&self, fn_salt: u64) -> rand::rngs::SmallRng {
2180 use crate::rng::{compose_seed, small_rng_from_lanes};
2181 let (sheet_id, row, col) = self
2182 .current_cell()
2183 .map(|c| (c.sheet_id as u32, c.coord.row(), c.coord.col()))
2184 .unwrap_or((0, 0, 0));
2185 let epoch = match self.volatile_level() {
2187 VolatileLevel::OnRecalc => self.recalc_epoch(),
2188 _ => 0,
2189 };
2190 let (l0, l1) = compose_seed(self.workbook_seed(), sheet_id, row, col, fn_salt, epoch);
2191 small_rng_from_lanes(l0, l1)
2192 }
2193
2194 fn date_system(&self) -> crate::engine::DateSystem {
2196 crate::engine::DateSystem::Excel1900
2197 }
2198
2199 fn get_lookup_index(
2202 &self,
2203 _view: &RangeView<'_>,
2204 _axis: LookupAxis,
2205 ) -> Option<std::sync::Arc<LookupIndex>> {
2206 None
2207 }
2208
2209 fn get_criteria_mask(
2212 &self,
2213 _view: &RangeView<'_>,
2214 _col_in_view: usize,
2215 _pred: &crate::args::CriteriaPredicate,
2216 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2217 None
2218 }
2219
2220 fn get_row_visibility_mask(
2222 &self,
2223 _view: &RangeView<'_>,
2224 _mode: VisibilityMaskMode,
2225 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2226 None
2227 }
2228}
2229
2230pub struct DefaultFunctionContext<'a> {
2232 pub base: &'a dyn EvaluationContext,
2233 pub current: Option<CellRef>,
2234 pub current_sheet: &'a str,
2235}
2236
2237impl<'a> DefaultFunctionContext<'a> {
2238 pub fn new(
2239 base: &'a dyn EvaluationContext,
2240 current: Option<CellRef>,
2241 current_sheet: &'a str,
2242 ) -> Self {
2243 Self {
2244 base,
2245 current,
2246 current_sheet,
2247 }
2248 }
2249
2250 pub fn new_with_sheet(
2251 base: &'a dyn EvaluationContext,
2252 current: Option<CellRef>,
2253 current_sheet: &'a str,
2254 ) -> Self {
2255 Self::new(base, current, current_sheet)
2256 }
2257}
2258
2259impl<'a> FunctionContext<'a> for DefaultFunctionContext<'a> {
2260 fn locale(&self) -> crate::locale::Locale {
2261 self.base.locale()
2262 }
2263
2264 fn current_sheet(&self) -> &str {
2265 self.current_sheet
2266 }
2267
2268 fn workbook_sheet_count(&self) -> Option<usize> {
2269 self.base.workbook_sheet_count()
2270 }
2271
2272 fn sheet_index_by_name(&self, sheet: &str) -> Option<usize> {
2273 self.base.sheet_index_by_name(sheet)
2274 }
2275
2276 fn current_sheet_index(&self) -> Option<usize> {
2277 self.base.current_sheet_index(self.current_sheet)
2278 }
2279
2280 fn inspect_reference(
2281 &self,
2282 reference: &ReferenceType,
2283 ) -> Result<Option<ReferenceInfo>, ExcelError> {
2284 self.base.inspect_reference(reference, self.current_sheet)
2285 }
2286
2287 fn formula_text_at_cell(&self, cell: CellRef) -> Result<Option<String>, ExcelError> {
2288 self.base.formula_text_at_cell(cell)
2289 }
2290
2291 fn timezone(&self) -> &crate::timezone::TimeZoneSpec {
2292 self.base.timezone()
2293 }
2294
2295 fn clock(&self) -> &dyn crate::timezone::ClockProvider {
2296 self.base.clock()
2297 }
2298 fn thread_pool(&self) -> Option<&std::sync::Arc<rayon::ThreadPool>> {
2299 self.base.thread_pool()
2300 }
2301 fn cancellation_token(&self) -> Option<crate::engine::CancelToken> {
2302 self.base.cancellation_token()
2303 }
2304 fn chunk_hint(&self) -> Option<usize> {
2305 self.base.chunk_hint()
2306 }
2307
2308 fn volatile_level(&self) -> VolatileLevel {
2309 self.base.volatile_level()
2310 }
2311 fn workbook_seed(&self) -> u64 {
2312 self.base.workbook_seed()
2313 }
2314 fn recalc_epoch(&self) -> u64 {
2315 self.base.recalc_epoch()
2316 }
2317 fn current_cell(&self) -> Option<CellRef> {
2318 self.current
2319 }
2320
2321 fn resolve_range_view(
2322 &self,
2323 reference: &ReferenceType,
2324 current_sheet: &str,
2325 ) -> Result<RangeView<'a>, ExcelError> {
2326 self.base.resolve_range_view(reference, current_sheet)
2327 }
2328
2329 fn date_system(&self) -> crate::engine::DateSystem {
2332 self.base.date_system()
2333 }
2334
2335 fn get_lookup_index(
2336 &self,
2337 view: &RangeView<'_>,
2338 axis: LookupAxis,
2339 ) -> Option<std::sync::Arc<LookupIndex>> {
2340 self.base.build_lookup_index(view, axis)
2341 }
2342
2343 fn get_criteria_mask(
2344 &self,
2345 view: &RangeView<'_>,
2346 col_in_view: usize,
2347 pred: &crate::args::CriteriaPredicate,
2348 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2349 self.base.build_criteria_mask(view, col_in_view, pred)
2350 }
2351
2352 fn get_row_visibility_mask(
2353 &self,
2354 view: &RangeView<'_>,
2355 mode: VisibilityMaskMode,
2356 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2357 self.base.build_row_visibility_mask(view, mode)
2358 }
2359}