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 spill_reference(&self) -> Result<ReferenceType, ExcelError> {
430 match &self.expr {
431 ArgumentExpr::Ast(node) => self.interp.ast_spill_reference(node),
432 ArgumentExpr::Arena {
433 id,
434 data_store,
435 sheet_registry,
436 } => self
437 .interp
438 .arena_spill_reference(*id, data_store, sheet_registry),
439 }
440 }
441
442 pub(crate) fn has_reference_semantics(&self) -> bool {
448 self.reference_attempt().is_some()
449 }
450
451 pub(crate) fn may_return_reference(&self) -> bool {
456 match &self.expr {
457 ArgumentExpr::Ast(node) => match &node.node_type {
458 ASTNodeType::Reference { reference, .. } => match reference {
459 ReferenceType::NamedRange(name)
461 if self.interp.resolve_local_name(name).is_some() =>
462 {
463 self.interp.resolve_local_bound_reference(name).is_some()
464 }
465 _ => true,
466 },
467 ASTNodeType::BinaryOp { op, .. } => op == ":",
468 ASTNodeType::UnaryOp { op, .. } => op == "#",
469 ASTNodeType::Function { name, .. } => self
470 .interp
471 .context
472 .function_capabilities("", name)
473 .is_some_and(|caps| caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)),
474 _ => false,
475 },
476 ArgumentExpr::Arena { id, data_store, .. } => match data_store.get_node(*id) {
477 Some(crate::engine::arena::AstNodeData::Reference { ref_type, .. }) => {
478 match ref_type {
479 crate::engine::arena::CompactRefType::NamedRange(name_id)
481 if self
482 .interp
483 .resolve_local_name(data_store.resolve_ast_string(*name_id))
484 .is_some() =>
485 {
486 self.interp
487 .resolve_local_bound_reference(
488 data_store.resolve_ast_string(*name_id),
489 )
490 .is_some()
491 }
492 _ => true,
493 }
494 }
495 Some(crate::engine::arena::AstNodeData::BinaryOp { op_id, .. }) => {
496 data_store.resolve_ast_string(*op_id) == ":"
497 }
498 Some(crate::engine::arena::AstNodeData::UnaryOp { op_id, .. }) => {
499 data_store.resolve_ast_string(*op_id) == "#"
500 }
501 Some(crate::engine::arena::AstNodeData::Function { name_id, .. }) => self
502 .interp
503 .context
504 .function_capabilities("", data_store.resolve_ast_string(*name_id))
505 .is_some_and(|caps| caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)),
506 _ => false,
507 },
508 }
509 }
510
511 pub fn value(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
512 self.cached_value
513 .get_or_init(|| self.compute_value())
514 .clone()
515 }
516
517 pub(crate) fn value_for_text(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
523 if self.is_omitted() {
524 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(
525 String::new(),
526 )))
527 } else {
528 self.value()
529 }
530 }
531
532 pub(crate) fn resolve_once_for_text(&self) -> Result<ResolvedArgument<'b>, ExcelError> {
533 if self.is_omitted() {
534 Ok(ResolvedArgument::Value(crate::traits::CalcValue::Scalar(
535 LiteralValue::Text(String::new()),
536 )))
537 } else {
538 self.resolve_once()
539 }
540 }
541
542 fn compute_value(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
543 match &self.expr {
544 ArgumentExpr::Ast(node) => match &node.node_type {
545 ASTNodeType::Literal(v) => Ok(crate::traits::CalcValue::Scalar(v.clone())),
546 ASTNodeType::Omitted => {
549 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
550 }
551 _ => self.interp.evaluate_ast(node),
552 },
553 ArgumentExpr::Arena {
554 id,
555 data_store,
556 sheet_registry,
557 } => {
558 if matches!(
559 data_store.get_node(*id),
560 Some(crate::engine::arena::AstNodeData::Omitted)
561 ) {
562 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
563 } else {
564 self.interp
565 .evaluate_arena_ast(*id, data_store, sheet_registry)
566 }
567 }
568 }
569 }
570
571 pub fn value_with_env(
572 &self,
573 env: crate::interpreter::LocalEnv,
574 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
575 let scoped = self.interp.with_local_env(env);
576 match &self.expr {
577 ArgumentExpr::Ast(node) => match &node.node_type {
578 ASTNodeType::Literal(v) => Ok(crate::traits::CalcValue::Scalar(v.clone())),
579 ASTNodeType::Omitted => {
580 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
581 }
582 _ => scoped.evaluate_ast(node),
583 },
584 ArgumentExpr::Arena {
585 id,
586 data_store,
587 sheet_registry,
588 } => {
589 if matches!(
590 data_store.get_node(*id),
591 Some(crate::engine::arena::AstNodeData::Omitted)
592 ) {
593 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
594 } else {
595 scoped.evaluate_arena_ast(*id, data_store, sheet_registry)
596 }
597 }
598 }
599 }
600
601 pub fn current_env(&self) -> crate::interpreter::LocalEnv {
602 self.interp.local_env().clone()
603 }
604
605 pub(crate) fn bound_reference_in_env(
612 &self,
613 env: &crate::interpreter::LocalEnv,
614 ) -> Option<ReferenceType> {
615 match &self.expr {
616 ArgumentExpr::Ast(node) => match &node.node_type {
617 ASTNodeType::Reference { reference, .. } => {
618 if let ReferenceType::NamedRange(name) = reference
619 && let Some(binding) = env.lookup(name)
620 {
621 return match binding {
623 crate::interpreter::LocalBinding::ValueWithReference {
624 reference,
625 ..
626 } => Some(reference),
627 _ => None,
628 };
629 }
630 self.interp.reference_for_current_offset(reference).ok()
631 }
632 ASTNodeType::BinaryOp { op, .. } if op == ":" => self
633 .interp
634 .with_local_env(env.clone())
635 .evaluate_ast_as_reference(node)
636 .ok(),
637 ASTNodeType::UnaryOp { op, expr } if op == "#" => self
638 .interp
639 .with_local_env(env.clone())
640 .ast_spill_reference(expr)
641 .ok(),
642 _ => None,
643 },
644 ArgumentExpr::Arena {
645 id,
646 data_store,
647 sheet_registry,
648 } => match data_store.get_node(*id) {
649 Some(crate::engine::arena::AstNodeData::Reference { ref_type, .. }) => {
650 if let crate::engine::arena::CompactRefType::NamedRange(name_id) = ref_type
651 && let Some(binding) = env.lookup(data_store.resolve_ast_string(*name_id))
652 {
653 return match binding {
654 crate::interpreter::LocalBinding::ValueWithReference {
655 reference,
656 ..
657 } => Some(reference),
658 _ => None,
659 };
660 }
661 let reference =
662 data_store.reconstruct_reference_type_for_eval(ref_type, sheet_registry);
663 self.interp.reference_for_current_offset(&reference).ok()
664 }
665 Some(crate::engine::arena::AstNodeData::BinaryOp { op_id, .. })
666 if data_store.resolve_ast_string(*op_id) == ":" =>
667 {
668 self.interp
669 .with_local_env(env.clone())
670 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry)
671 .ok()
672 }
673 Some(crate::engine::arena::AstNodeData::UnaryOp { op_id, expr_id })
674 if data_store.resolve_ast_string(*op_id) == "#" =>
675 {
676 self.interp
677 .with_local_env(env.clone())
678 .arena_spill_reference(*expr_id, data_store, sheet_registry)
679 .ok()
680 }
681 _ => None,
682 },
683 }
684 }
685
686 pub fn inline_array_literal(&self) -> Result<Option<Vec<Vec<LiteralValue>>>, ExcelError> {
687 match &self.expr {
688 ArgumentExpr::Ast(node) => match &node.node_type {
689 ASTNodeType::Literal(LiteralValue::Array(arr)) => Ok(Some(arr.clone())),
690 _ => Ok(None),
691 },
692 ArgumentExpr::Arena {
693 id,
694 data_store,
695 sheet_registry,
696 } => {
697 let node = data_store.get_node(*id).ok_or_else(|| {
698 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
699 })?;
700 match node {
701 crate::engine::arena::AstNodeData::Literal(vref) => {
702 match data_store.retrieve_value(*vref) {
703 LiteralValue::Array(arr) => Ok(Some(arr)),
704 _ => Ok(None),
705 }
706 }
707 _ => {
708 let _ = sheet_registry;
711 Ok(None)
712 }
713 }
714 }
715 }
716 }
717
718 fn local_named_reference(&self, name: &str) -> Option<Result<ReferenceType, ExcelError>> {
737 self.interp.resolve_local_name(name)?;
739 Some(
740 self.interp
741 .resolve_local_bound_reference(name)
742 .ok_or_else(|| {
743 ExcelError::new(ExcelErrorKind::Value)
744 .with_message("LET/LAMBDA local is not a reference")
745 }),
746 )
747 }
748
749 fn reference_for_eval(&self) -> Result<ReferenceType, ExcelError> {
750 match &self.expr {
751 ArgumentExpr::Ast(node) => match &node.node_type {
752 ASTNodeType::Reference { reference, .. } => {
753 if let ReferenceType::NamedRange(name) = reference
756 && let Some(local) = self.local_named_reference(name)
757 {
758 return local;
759 }
760 self.interp.reference_for_current_offset(reference)
761 }
762 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
763 self.interp.evaluate_ast_as_reference(node)
764 }
765 ASTNodeType::UnaryOp { op, expr } if op == "#" => {
766 self.interp.ast_spill_reference(expr)
767 }
768 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
769 .with_message("Expected a reference (by-ref argument)")),
770 },
771 ArgumentExpr::Arena {
772 id,
773 data_store,
774 sheet_registry,
775 } => {
776 let node = data_store.get_node(*id).ok_or_else(|| {
777 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
778 })?;
779 match node {
780 crate::engine::arena::AstNodeData::Reference { ref_type, .. } => {
781 if let crate::engine::arena::CompactRefType::NamedRange(name_id) = ref_type
783 && let Some(local) =
784 self.local_named_reference(data_store.resolve_ast_string(*name_id))
785 {
786 return local;
787 }
788 let reference = data_store
789 .reconstruct_reference_type_for_eval(ref_type, sheet_registry);
790 self.interp.reference_for_current_offset(&reference)
791 }
792 crate::engine::arena::AstNodeData::Function { .. }
793 | crate::engine::arena::AstNodeData::BinaryOp { .. } => self
794 .interp
795 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry),
796 crate::engine::arena::AstNodeData::UnaryOp { op_id, expr_id }
797 if data_store.resolve_ast_string(*op_id) == "#" =>
798 {
799 self.interp
800 .arena_spill_reference(*expr_id, data_store, sheet_registry)
801 }
802 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
803 .with_message("Expected a reference (by-ref argument)")),
804 }
805 }
806 }
807 }
808
809 fn function_resolution_attempt(
810 &self,
811 ) -> Option<Result<crate::function::FunctionResolution<'b>, ExcelError>> {
812 match &self.expr {
813 ArgumentExpr::Ast(node) => {
814 let ASTNodeType::Function { name, args } = &node.node_type else {
815 return None;
816 };
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 handles: Vec<_> = args
833 .iter()
834 .map(|arg| ArgumentHandle::new(arg, self.interp))
835 .collect();
836 let ctx = DefaultFunctionContext::new_with_sheet(
837 self.interp.context,
838 None,
839 self.interp.current_sheet(),
840 );
841 Some(fun.resolve_reference_or_value(&handles, &ctx, &|| self.value()))
842 }
843 ArgumentExpr::Arena {
844 id,
845 data_store,
846 sheet_registry,
847 } => {
848 let node = match data_store.get_node(*id) {
849 Some(node) => node,
850 None => {
851 return Some(Err(
852 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
853 ));
854 }
855 };
856 let crate::engine::arena::AstNodeData::Function { name_id, .. } = node else {
857 return None;
858 };
859 let name = data_store.resolve_ast_string(*name_id);
860 if !self
861 .interp
862 .context
863 .function_capabilities("", name)
864 .is_some_and(|caps| caps.contains(crate::function::FnCaps::RETURNS_REFERENCE))
865 {
866 return None;
867 }
868 let fun = match self.interp.context.get_function("", name) {
869 Some(fun) => fun,
870 None => {
871 return Some(Err(ExcelError::new(ExcelErrorKind::Name)
872 .with_message(format!("Unknown function: {name}"))));
873 }
874 };
875 let args = match data_store.get_args(*id) {
876 Some(args) => args,
877 None => {
878 return Some(Err(ExcelError::new(ExcelErrorKind::Value)
879 .with_message("Missing function args")));
880 }
881 };
882 let handles: Vec<_> = args
883 .iter()
884 .copied()
885 .map(|arg_id| {
886 ArgumentHandle::new_arena(arg_id, self.interp, data_store, sheet_registry)
887 })
888 .collect();
889 let ctx = DefaultFunctionContext::new_with_sheet(
890 self.interp.context,
891 None,
892 self.interp.current_sheet(),
893 );
894 Some(fun.resolve_reference_or_value(&handles, &ctx, &|| self.value()))
895 }
896 }
897 }
898
899 fn reference_attempt(&self) -> Option<Result<ReferenceType, ExcelError>> {
900 match &self.expr {
901 ArgumentExpr::Ast(node) => match &node.node_type {
902 ASTNodeType::Reference { reference, .. } => {
903 if let ReferenceType::NamedRange(name) = reference
908 && self.interp.resolve_local_name(name).is_some()
909 {
910 return self.interp.resolve_local_bound_reference(name).map(Ok);
911 }
912 Some(self.interp.reference_for_current_offset(reference))
913 }
914 ASTNodeType::BinaryOp { op, .. } if op == ":" => {
915 Some(self.interp.evaluate_ast_as_reference(node))
916 }
917 ASTNodeType::UnaryOp { op, expr } if op == "#" => {
918 Some(self.interp.ast_spill_reference(expr))
919 }
920 ASTNodeType::Function { name, .. }
921 if self
922 .interp
923 .context
924 .function_capabilities("", name)
925 .is_some_and(|caps| {
926 caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)
927 }) =>
928 {
929 self.interp.try_evaluate_ast_as_reference(node)
930 }
931 _ => None,
932 },
933 ArgumentExpr::Arena {
934 id,
935 data_store,
936 sheet_registry,
937 } => {
938 let node = match data_store.get_node(*id) {
939 Some(node) => node,
940 None => {
941 return Some(Err(
942 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
943 ));
944 }
945 };
946 match node {
947 crate::engine::arena::AstNodeData::Reference { ref_type, .. } => {
948 if let crate::engine::arena::CompactRefType::NamedRange(name_id) = ref_type
950 {
951 let name = data_store.resolve_ast_string(*name_id);
952 if self.interp.resolve_local_name(name).is_some() {
953 return self.interp.resolve_local_bound_reference(name).map(Ok);
954 }
955 }
956 let reference = data_store
957 .reconstruct_reference_type_for_eval(ref_type, sheet_registry);
958 Some(self.interp.reference_for_current_offset(&reference))
959 }
960 crate::engine::arena::AstNodeData::BinaryOp { op_id, .. }
961 if data_store.resolve_ast_string(*op_id) == ":" =>
962 {
963 Some(self.interp.evaluate_arena_ast_as_reference(
964 *id,
965 data_store,
966 sheet_registry,
967 ))
968 }
969 crate::engine::arena::AstNodeData::UnaryOp { op_id, expr_id }
970 if data_store.resolve_ast_string(*op_id) == "#" =>
971 {
972 Some(self.interp.arena_spill_reference(
973 *expr_id,
974 data_store,
975 sheet_registry,
976 ))
977 }
978 crate::engine::arena::AstNodeData::Function { name_id, .. } => {
979 let name = data_store.resolve_ast_string(*name_id);
980 if self
981 .interp
982 .context
983 .function_capabilities("", name)
984 .is_some_and(|caps| {
985 caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)
986 })
987 {
988 self.interp.try_evaluate_arena_ast_as_reference(
989 *id,
990 data_store,
991 sheet_registry,
992 )
993 } else {
994 None
995 }
996 }
997 _ => None,
998 }
999 }
1000 }
1001 }
1002
1003 pub(crate) fn resolve_reference_or_value(
1004 &self,
1005 ) -> Result<crate::function::FunctionResolution<'b>, ExcelError> {
1006 let resolved = self
1007 .cached_reference_or_value
1008 .get_or_init(|| self.compute_reference_or_value())
1009 .clone();
1010 if let Ok(crate::function::FunctionResolution::Value(value)) = &resolved {
1011 let _ = self.cached_value.set(Ok(value.clone()));
1012 }
1013 resolved
1014 }
1015
1016 fn compute_reference_or_value(
1017 &self,
1018 ) -> Result<crate::function::FunctionResolution<'b>, ExcelError> {
1019 if let Some(result) = self.function_resolution_attempt() {
1020 return result;
1021 }
1022 if let Some(reference) = self.reference_attempt() {
1023 return Ok(match reference {
1024 Ok(reference) => crate::function::FunctionResolution::Reference(reference),
1025 Err(error) => crate::function::FunctionResolution::ReferenceError(error),
1026 });
1027 }
1028 self.value().map(crate::function::FunctionResolution::Value)
1029 }
1030
1031 pub(crate) fn resolve_once(&self) -> Result<ResolvedArgument<'b>, ExcelError> {
1037 self.cached_resolved
1038 .get_or_init(|| self.compute_resolved_argument())
1039 .clone()
1040 }
1041
1042 pub(crate) fn with_context_cancel_token(&self, view: RangeView<'b>) -> RangeView<'b> {
1043 match self.interp.context.cancellation_token() {
1044 Some(token) => view.with_cancel_token(Some(token)),
1045 None => view,
1046 }
1047 }
1048
1049 fn compute_resolved_argument(&self) -> Result<ResolvedArgument<'b>, ExcelError> {
1050 let value = match self.resolve_reference_or_value()? {
1051 crate::function::FunctionResolution::Reference(reference) => {
1052 return match self
1053 .interp
1054 .context
1055 .resolve_range_view(&reference, self.interp.current_sheet())
1056 {
1057 Ok(view) => Ok(ResolvedArgument::Range(
1058 self.with_context_cancel_token(view),
1059 )),
1060 Err(error) if error.kind == ExcelErrorKind::Cancelled => Err(error),
1061 Err(error) => Ok(ResolvedArgument::ReferenceError(error)),
1062 };
1063 }
1064 crate::function::FunctionResolution::ReferenceError(error)
1065 if error.kind == ExcelErrorKind::Cancelled =>
1066 {
1067 return Err(error);
1068 }
1069 crate::function::FunctionResolution::ReferenceError(error) => {
1070 return Ok(ResolvedArgument::ReferenceError(error));
1071 }
1072 crate::function::FunctionResolution::Value(value) => value,
1073 };
1074
1075 match value {
1076 CalcValue::Range(view) => Ok(ResolvedArgument::Range(
1077 self.with_context_cancel_token(view),
1078 )),
1079 CalcValue::Scalar(LiteralValue::Array(rows)) => {
1080 let view = RangeView::try_from_owned_rows(
1081 rows,
1082 self.interp.context.date_system(),
1083 self.interp.context.cancellation_token(),
1084 )?;
1085 Ok(ResolvedArgument::Range(view))
1086 }
1087 other => Ok(ResolvedArgument::Value(other)),
1088 }
1089 }
1090
1091 pub fn range(&self) -> Result<Box<dyn Range>, ExcelError> {
1092 match &self.expr {
1093 ArgumentExpr::Ast(node) => match &node.node_type {
1094 ASTNodeType::Reference { reference, .. } => {
1095 let reference = self.interp.reference_for_current_offset(reference)?;
1097 let view = self
1098 .interp
1099 .context
1100 .resolve_range_view(&reference, self.interp.current_sheet())?;
1101 let (rows, cols) = view.dims();
1102 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
1103 view.for_each_row(&mut |row| {
1104 let row_data: Vec<LiteralValue> = (0..cols)
1105 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
1106 .collect();
1107 out.push(row_data);
1108 Ok(())
1109 })?;
1110 Ok(Box::new(InMemoryRange::new(out)))
1111 }
1112 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
1113 let reference = self.reference_for_eval()?;
1114 let view = self
1115 .interp
1116 .context
1117 .resolve_range_view(&reference, self.interp.current_sheet())?;
1118 let (rows, cols) = view.dims();
1119 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
1120 view.for_each_row(&mut |row| {
1121 let row_data: Vec<LiteralValue> = (0..cols)
1122 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
1123 .collect();
1124 out.push(row_data);
1125 Ok(())
1126 })?;
1127 Ok(Box::new(InMemoryRange::new(out)))
1128 }
1129 ASTNodeType::Array(rows) => {
1130 let mut materialized = Vec::new();
1131 for row in rows {
1132 let mut materialized_row = Vec::new();
1133 for cell in row {
1134 materialized_row.push(self.interp.evaluate_ast(cell)?.into_literal());
1135 }
1136 materialized.push(materialized_row);
1137 }
1138 Ok(Box::new(InMemoryRange::new(materialized)))
1139 }
1140 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1141 .with_message(format!("Expected a range, got {:?}", node.node_type))),
1142 },
1143 ArgumentExpr::Arena { id, data_store, .. } => {
1144 let node = data_store.get_node(*id).ok_or_else(|| {
1145 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
1146 })?;
1147
1148 match node {
1149 crate::engine::arena::AstNodeData::Reference { .. }
1150 | crate::engine::arena::AstNodeData::Function { .. }
1151 | crate::engine::arena::AstNodeData::BinaryOp { .. } => {
1152 let reference = self.reference_for_eval()?;
1153 let view = self
1154 .interp
1155 .context
1156 .resolve_range_view(&reference, self.interp.current_sheet())?;
1157 let (rows, cols) = view.dims();
1158 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
1159 view.for_each_row(&mut |row| {
1160 let row_data: Vec<LiteralValue> = (0..cols)
1161 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
1162 .collect();
1163 out.push(row_data);
1164 Ok(())
1165 })?;
1166 Ok(Box::new(InMemoryRange::new(out)))
1167 }
1168 crate::engine::arena::AstNodeData::Array { .. } => {
1169 let (rows, cols, elements) =
1170 data_store.get_array_elems(*id).ok_or_else(|| {
1171 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
1172 })?;
1173 let rows_usize = rows as usize;
1174 let cols_usize = cols as usize;
1175 let mut materialized: Vec<Vec<LiteralValue>> =
1176 Vec::with_capacity(rows_usize);
1177 for r in 0..rows_usize {
1178 let mut row = Vec::with_capacity(cols_usize);
1179 for c in 0..cols_usize {
1180 let idx = r * cols_usize + c;
1181 let elem_id = elements.get(idx).copied().ok_or_else(|| {
1182 ExcelError::new(ExcelErrorKind::Value)
1183 .with_message("Invalid array")
1184 })?;
1185 let v = self.interp.evaluate_arena_ast(
1186 elem_id,
1187 data_store,
1188 self.sheet_registry(),
1189 )?;
1190 row.push(v.into_literal());
1191 }
1192 materialized.push(row);
1193 }
1194 Ok(Box::new(InMemoryRange::new(materialized)))
1195 }
1196 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1197 .with_message("Argument cannot be interpreted as a range.")),
1198 }
1199 }
1200 }
1201 }
1202
1203 fn sheet_registry(&self) -> &crate::engine::sheet_registry::SheetRegistry {
1204 match &self.expr {
1205 ArgumentExpr::Ast(_) => {
1206 unreachable!("sheet_registry only used for arena ArgumentHandle")
1208 }
1209 ArgumentExpr::Arena { sheet_registry, .. } => sheet_registry,
1210 }
1211 }
1212
1213 pub fn range_view(&self) -> Result<RangeView<'b>, ExcelError> {
1221 match self.resolve_once()? {
1222 ResolvedArgument::Range(view) => Ok(view),
1223 ResolvedArgument::ReferenceError(error) => Err(error),
1226 ResolvedArgument::Value(CalcValue::Range(view)) => {
1231 Ok(self.with_context_cancel_token(view))
1232 }
1233 ResolvedArgument::Value(CalcValue::Scalar(LiteralValue::Array(rows))) => {
1234 RangeView::try_from_owned_rows(
1235 rows,
1236 self.interp.context.date_system(),
1237 self.interp.context.cancellation_token(),
1238 )
1239 }
1240 ResolvedArgument::Value(_) => Err(ExcelError::new(ExcelErrorKind::Ref)
1241 .with_message("Argument cannot be interpreted as a range.")),
1242 }
1243 }
1244
1245 pub fn range_view_or_scalar(&self) -> Result<RangeView<'b>, ExcelError> {
1265 match self.resolve_once()? {
1266 ResolvedArgument::Range(view) => Ok(view),
1267 ResolvedArgument::ReferenceError(error) => Err(error),
1268 ResolvedArgument::Value(CalcValue::Range(view)) => {
1269 Ok(self.with_context_cancel_token(view))
1270 }
1271 ResolvedArgument::Value(CalcValue::Scalar(LiteralValue::Array(rows))) => {
1272 RangeView::try_from_owned_rows(
1273 rows,
1274 self.interp.context.date_system(),
1275 self.interp.context.cancellation_token(),
1276 )
1277 }
1278 ResolvedArgument::Value(CalcValue::Scalar(LiteralValue::Error(error))) => Err(error),
1281 ResolvedArgument::Value(
1282 CalcValue::Scalar(scalar) | CalcValue::AnnotatedScalar(scalar, _),
1283 ) => RangeView::try_from_owned_rows(
1284 vec![vec![scalar]],
1285 self.interp.context.date_system(),
1286 self.interp.context.cancellation_token(),
1287 ),
1288 ResolvedArgument::Value(CalcValue::Callable(_)) => {
1290 Err(ExcelError::new(ExcelErrorKind::Ref)
1291 .with_message("Argument cannot be interpreted as a range."))
1292 }
1293 }
1294 }
1295
1296 pub fn value_or_range(&self) -> Result<EvaluatedArg<'_>, ExcelError> {
1297 self.range().map(EvaluatedArg::Range).or_else(|_| {
1298 self.value()
1299 .map(|cv| EvaluatedArg::LiteralValue(Cow::Owned(cv.into_literal())))
1300 })
1301 }
1302
1303 pub fn lazy_values_owned(
1308 &'a self,
1309 ) -> Result<Box<dyn Iterator<Item = LiteralValue> + 'a>, ExcelError> {
1310 fn resolved_values<'a, 'b>(
1314 handle: &'a ArgumentHandle<'a, 'b>,
1315 ) -> Result<Box<dyn Iterator<Item = LiteralValue> + 'a>, ExcelError> {
1316 match handle.resolve_once()? {
1317 ResolvedArgument::Range(view) => {
1318 let mut values = Vec::new();
1319 view.for_each_cell(&mut |value| {
1320 values.push(value.clone());
1321 Ok(())
1322 })?;
1323 Ok(Box::new(values.into_iter()))
1324 }
1325 ResolvedArgument::ReferenceError(error) => Err(error),
1326 ResolvedArgument::Value(value) => {
1327 Ok(Box::new(std::iter::once(value.into_literal())))
1328 }
1329 }
1330 }
1331
1332 match &self.expr {
1333 ArgumentExpr::Ast(node) => match &node.node_type {
1334 ASTNodeType::Reference { .. } => resolved_values(self),
1335 ASTNodeType::Array(rows) => {
1336 struct ArrayEvalIter<'a, 'b> {
1337 rows: &'a [Vec<ASTNode>],
1338 r: usize,
1339 c: usize,
1340 interp: &'a Interpreter<'b>,
1341 }
1342 impl<'a, 'b> Iterator for ArrayEvalIter<'a, 'b> {
1343 type Item = LiteralValue;
1344 fn next(&mut self) -> Option<Self::Item> {
1345 if self.rows.is_empty() {
1346 return None;
1347 }
1348 let rows = self.rows;
1349 let mut r = self.r;
1350 let mut c = self.c;
1351 if r >= rows.len() {
1352 return None;
1353 }
1354 let node = &rows[r][c];
1355 c += 1;
1357 if c >= rows[r].len() {
1358 r += 1;
1359 c = 0;
1360 }
1361 self.r = r;
1362 self.c = c;
1363 match self.interp.evaluate_ast(node) {
1364 Ok(cv) => Some(cv.into_literal()),
1365 Err(e) => Some(LiteralValue::Error(e)),
1366 }
1367 }
1368 }
1369 let it = ArrayEvalIter {
1370 rows,
1371 r: 0,
1372 c: 0,
1373 interp: self.interp,
1374 };
1375 Ok(Box::new(it))
1376 }
1377 _ => {
1378 let v = self.value()?.into_literal();
1380 Ok(Box::new(std::iter::once(v)))
1381 }
1382 },
1383 ArgumentExpr::Arena {
1384 id,
1385 data_store,
1386 sheet_registry,
1387 } => {
1388 let node = data_store.get_node(*id).ok_or_else(|| {
1389 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
1390 })?;
1391
1392 match node {
1393 crate::engine::arena::AstNodeData::Reference { .. } => resolved_values(self),
1394 crate::engine::arena::AstNodeData::Array { .. } => {
1395 let (rows, cols, elements) =
1396 data_store.get_array_elems(*id).ok_or_else(|| {
1397 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
1398 })?;
1399
1400 struct ArenaArrayEvalIter<'a, 'b> {
1401 elements: &'a [crate::engine::arena::AstNodeId],
1402 idx: usize,
1403 interp: &'a Interpreter<'b>,
1404 data_store: &'a crate::engine::arena::DataStore,
1405 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
1406 }
1407
1408 impl<'a, 'b> Iterator for ArenaArrayEvalIter<'a, 'b> {
1409 type Item = LiteralValue;
1410
1411 fn next(&mut self) -> Option<Self::Item> {
1412 let id = self.elements.get(self.idx).copied()?;
1413 self.idx += 1;
1414 match self.interp.evaluate_arena_ast(
1415 id,
1416 self.data_store,
1417 self.sheet_registry,
1418 ) {
1419 Ok(cv) => Some(cv.into_literal()),
1420 Err(e) => Some(LiteralValue::Error(e)),
1421 }
1422 }
1423 }
1424
1425 let _ = (rows, cols);
1426 let it = ArenaArrayEvalIter {
1427 elements,
1428 idx: 0,
1429 interp: self.interp,
1430 data_store,
1431 sheet_registry,
1432 };
1433 Ok(Box::new(it))
1434 }
1435 _ => {
1436 let v = self
1437 .interp
1438 .evaluate_arena_ast(*id, data_store, sheet_registry)?;
1439 Ok(Box::new(std::iter::once(v.into_literal())))
1440 }
1441 }
1442 }
1443 }
1444 }
1445
1446 pub fn ast(&self) -> &ASTNode {
1447 match &self.expr {
1448 ArgumentExpr::Ast(node) => node,
1449 ArgumentExpr::Arena {
1450 id,
1451 data_store,
1452 sheet_registry,
1453 } => self.cached_ast.get_or_init(|| {
1454 data_store
1455 .retrieve_ast(*id, sheet_registry)
1456 .unwrap_or_else(|| ASTNode {
1457 node_type: ASTNodeType::Literal(LiteralValue::Error(
1458 ExcelError::new(ExcelErrorKind::Value)
1459 .with_message("Missing formula AST"),
1460 )),
1461 source_token: None,
1462 contains_volatile: false,
1463 })
1464 }),
1465 }
1466 }
1467
1468 pub fn as_reference(&self) -> Result<&ReferenceType, ExcelError> {
1471 match &self.expr {
1472 ArgumentExpr::Ast(node) => match &node.node_type {
1473 ASTNodeType::Reference { reference, .. } => {
1474 if let ReferenceType::NamedRange(name) = reference
1476 && let Some(local) = self.local_named_reference(name)
1477 {
1478 let bound = local?;
1479 return Ok(self.cached_ref.get_or_init(|| bound));
1480 }
1481 Ok(reference)
1482 }
1483 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1484 .with_message("Expected a reference (by-ref argument)")),
1485 },
1486 ArgumentExpr::Arena { .. } => {
1487 let reference = self.reference_for_eval()?;
1488 Ok(self.cached_ref.get_or_init(|| reference))
1489 }
1490 }
1491 }
1492
1493 pub fn as_reference_or_eval(&self) -> Result<ReferenceType, ExcelError> {
1496 match &self.expr {
1497 ArgumentExpr::Ast(node) => match &node.node_type {
1498 ASTNodeType::Reference { reference, .. } => {
1499 if let ReferenceType::NamedRange(name) = reference
1501 && let Some(local) = self.local_named_reference(name)
1502 {
1503 return local;
1504 }
1505 self.interp.reference_for_current_offset(reference)
1506 }
1507 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
1508 self.interp.evaluate_ast_as_reference(node)
1509 }
1510 ASTNodeType::UnaryOp { op, expr } if op == "#" => {
1511 self.interp.ast_spill_reference(expr)
1512 }
1513 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1514 .with_message("Argument is not a reference")),
1515 },
1516 ArgumentExpr::Arena {
1517 id,
1518 data_store,
1519 sheet_registry,
1520 } => {
1521 let node = data_store.get_node(*id).ok_or_else(|| {
1522 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
1523 })?;
1524
1525 match node {
1526 crate::engine::arena::AstNodeData::Reference { .. } => {
1527 self.reference_for_eval()
1528 }
1529 crate::engine::arena::AstNodeData::Function { .. }
1530 | crate::engine::arena::AstNodeData::BinaryOp { .. } => self
1531 .interp
1532 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry),
1533 crate::engine::arena::AstNodeData::UnaryOp { op_id, expr_id }
1534 if data_store.resolve_ast_string(*op_id) == "#" =>
1535 {
1536 self.interp
1537 .arena_spill_reference(*expr_id, data_store, sheet_registry)
1538 }
1539 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1540 .with_message("Argument is not a reference")),
1541 }
1542 }
1543 }
1544 }
1545
1546 pub fn matches_kind(&self, k: formualizer_common::ArgKind) -> Result<bool, ExcelError> {
1548 Ok(match k {
1549 formualizer_common::ArgKind::Any => true,
1550 formualizer_common::ArgKind::Range => self.range().is_ok(),
1551 formualizer_common::ArgKind::Number => matches!(
1552 self.value()?.into_literal(),
1553 LiteralValue::Number(_) | LiteralValue::Int(_)
1554 ),
1555 formualizer_common::ArgKind::Text => {
1556 matches!(self.value()?.into_literal(), LiteralValue::Text(_))
1557 }
1558 formualizer_common::ArgKind::Logical => {
1559 matches!(self.value()?.into_literal(), LiteralValue::Boolean(_))
1560 }
1561 })
1562 }
1563}
1564
1565#[derive(Debug, Clone)]
1567pub struct InMemoryRange {
1568 data: Vec<Vec<LiteralValue>>,
1569}
1570impl InMemoryRange {
1571 pub fn new(d: Vec<Vec<LiteralValue>>) -> Self {
1572 Self { data: d }
1573 }
1574}
1575impl Range for InMemoryRange {
1576 fn get(&self, r: usize, c: usize) -> Result<LiteralValue, ExcelError> {
1577 Ok(self
1578 .data
1579 .get(r)
1580 .and_then(|row| row.get(c))
1581 .cloned()
1582 .unwrap_or(LiteralValue::Empty))
1583 }
1584 fn dimensions(&self) -> (usize, usize) {
1585 (self.data.len(), self.data.first().map_or(0, |r| r.len()))
1586 }
1587 fn as_any(&self) -> &dyn Any {
1588 self
1589 }
1590}
1591
1592pub trait Table: Debug + Send + Sync {
1595 fn get_cell(&self, row: usize, column: &str) -> Result<LiteralValue, ExcelError>;
1596 fn get_column(&self, column: &str) -> Result<Box<dyn Range>, ExcelError>;
1597 fn columns(&self) -> Vec<String> {
1599 vec![]
1600 }
1601 fn data_height(&self) -> usize {
1603 0
1604 }
1605 fn has_headers(&self) -> bool {
1607 false
1608 }
1609 fn has_totals(&self) -> bool {
1611 false
1612 }
1613 fn headers_row(&self) -> Option<Box<dyn Range>> {
1615 None
1616 }
1617 fn totals_row(&self) -> Option<Box<dyn Range>> {
1619 None
1620 }
1621 fn data_body(&self) -> Option<Box<dyn Range>> {
1623 None
1624 }
1625 fn clone_box(&self) -> Box<dyn Table>;
1626}
1627impl Table for Box<dyn Table> {
1628 fn get_cell(&self, r: usize, c: &str) -> Result<LiteralValue, ExcelError> {
1629 (**self).get_cell(r, c)
1630 }
1631 fn get_column(&self, c: &str) -> Result<Box<dyn Range>, ExcelError> {
1632 (**self).get_column(c)
1633 }
1634 fn columns(&self) -> Vec<String> {
1635 (**self).columns()
1636 }
1637 fn data_height(&self) -> usize {
1638 (**self).data_height()
1639 }
1640 fn has_headers(&self) -> bool {
1641 (**self).has_headers()
1642 }
1643 fn has_totals(&self) -> bool {
1644 (**self).has_totals()
1645 }
1646 fn headers_row(&self) -> Option<Box<dyn Range>> {
1647 (**self).headers_row()
1648 }
1649 fn totals_row(&self) -> Option<Box<dyn Range>> {
1650 (**self).totals_row()
1651 }
1652 fn data_body(&self) -> Option<Box<dyn Range>> {
1653 (**self).data_body()
1654 }
1655 fn clone_box(&self) -> Box<dyn Table> {
1656 (**self).clone_box()
1657 }
1658}
1659
1660pub trait ReferenceResolver: Send + Sync {
1663 fn resolve_cell_reference(
1664 &self,
1665 sheet: Option<&str>,
1666 row: u32,
1667 col: u32,
1668 ) -> Result<LiteralValue, ExcelError>;
1669}
1670pub trait RangeResolver: Send + Sync {
1671 fn resolve_range_reference(
1672 &self,
1673 sheet: Option<&str>,
1674 sr: Option<u32>,
1675 sc: Option<u32>,
1676 er: Option<u32>,
1677 ec: Option<u32>,
1678 ) -> Result<Box<dyn Range>, ExcelError>;
1679}
1680pub trait NamedRangeResolver: Send + Sync {
1681 fn resolve_named_range_reference(
1682 &self,
1683 name: &str,
1684 ) -> Result<Vec<Vec<LiteralValue>>, ExcelError>;
1685}
1686pub trait TableResolver: Send + Sync {
1687 fn resolve_table_reference(
1688 &self,
1689 tref: &formualizer_parse::parser::TableReference,
1690 ) -> Result<Box<dyn Table>, ExcelError>;
1691}
1692
1693pub trait SourceResolver: Send + Sync {
1694 fn source_scalar_version(&self, _name: &str) -> Option<u64> {
1695 None
1696 }
1697
1698 fn resolve_source_scalar(&self, name: &str) -> Result<LiteralValue, ExcelError> {
1699 Err(ExcelError::new(ExcelErrorKind::NImpl)
1700 .with_message(format!("Source scalar not supported: {name}")))
1701 }
1702
1703 fn source_table_version(&self, _name: &str) -> Option<u64> {
1704 None
1705 }
1706
1707 fn resolve_source_table(&self, name: &str) -> Result<Box<dyn Table>, ExcelError> {
1708 Err(ExcelError::new(ExcelErrorKind::NImpl)
1709 .with_message(format!("Source table not supported: {name}")))
1710 }
1711}
1712
1713pub trait Resolver: ReferenceResolver + RangeResolver + NamedRangeResolver + TableResolver {
1714 fn resolve_range_like(&self, r: &ReferenceType) -> Result<Box<dyn Range>, ExcelError> {
1715 match r {
1716 ReferenceType::Range {
1717 sheet,
1718 start_row,
1719 start_col,
1720 end_row,
1721 end_col,
1722 ..
1723 } => self.resolve_range_reference(
1724 sheet.as_deref(),
1725 *start_row,
1726 *start_col,
1727 *end_row,
1728 *end_col,
1729 ),
1730 ReferenceType::External(_) => Err(ExcelError::new(ExcelErrorKind::NImpl)
1731 .with_message("External references are not supported by Resolver".to_string())),
1732 ReferenceType::Table(tref) => {
1733 let t = self.resolve_table_reference(tref)?;
1734 match &tref.specifier {
1735 Some(TableSpecifier::Column(c)) => t.get_column(c),
1736 Some(TableSpecifier::ColumnRange(start, end)) => {
1737 let cols = t.columns();
1739 let start_key = start.to_lowercase();
1740 let end_key = end.to_lowercase();
1741 let start_idx = cols.iter().position(|n| n.to_lowercase() == start_key);
1742 let end_idx = cols.iter().position(|n| n.to_lowercase() == end_key);
1743 if let (Some(mut si), Some(mut ei)) = (start_idx, end_idx) {
1744 if si > ei {
1745 std::mem::swap(&mut si, &mut ei);
1746 }
1747 let h = t.data_height();
1749 let w = ei - si + 1;
1750 let mut rows = vec![vec![LiteralValue::Empty; w]; h];
1751 for (offset, ci) in (si..=ei).enumerate() {
1752 let cname = &cols[ci];
1753 let col_range = t.get_column(cname)?;
1754 let (rh, _) = col_range.dimensions();
1755 for (r, row) in rows.iter_mut().enumerate().take(h.min(rh)) {
1756 row[offset] = col_range.get(r, 0)?;
1757 }
1758 }
1759 Ok(Box::new(InMemoryRange::new(rows)))
1760 } else {
1761 Err(ExcelError::new(ExcelErrorKind::Ref).with_message(
1762 "Column range refers to unknown column(s)".to_string(),
1763 ))
1764 }
1765 }
1766 Some(TableSpecifier::SpecialItem(
1767 formualizer_parse::parser::SpecialItem::Headers,
1768 )) => {
1769 if let Some(h) = t.headers_row() {
1770 Ok(h)
1771 } else {
1772 Ok(Box::new(InMemoryRange::new(vec![])))
1773 }
1774 }
1775 Some(TableSpecifier::SpecialItem(
1776 formualizer_parse::parser::SpecialItem::Totals,
1777 )) => {
1778 if let Some(tr) = t.totals_row() {
1779 Ok(tr)
1780 } else {
1781 Ok(Box::new(InMemoryRange::new(vec![])))
1782 }
1783 }
1784 Some(TableSpecifier::SpecialItem(
1785 formualizer_parse::parser::SpecialItem::Data,
1786 )) => {
1787 if let Some(body) = t.data_body() {
1788 Ok(body)
1789 } else {
1790 Ok(Box::new(InMemoryRange::new(vec![])))
1791 }
1792 }
1793 Some(TableSpecifier::SpecialItem(
1794 formualizer_parse::parser::SpecialItem::All,
1795 )) => {
1796 let mut out: Vec<Vec<LiteralValue>> = Vec::new();
1798 if let Some(h) = t.headers_row() {
1799 out.extend(h.iter_rows());
1800 }
1801 if let Some(body) = t.data_body() {
1802 out.extend(body.iter_rows());
1803 }
1804 if let Some(tr) = t.totals_row() {
1805 out.extend(tr.iter_rows());
1806 }
1807 Ok(Box::new(InMemoryRange::new(out)))
1808 }
1809 Some(TableSpecifier::SpecialItem(
1810 formualizer_parse::parser::SpecialItem::ThisRow,
1811 )) => Err(ExcelError::new(ExcelErrorKind::NImpl).with_message(
1812 "@ (This Row) requires table-aware context; not yet supported".to_string(),
1813 )),
1814 Some(TableSpecifier::All) => {
1815 let mut out: Vec<Vec<LiteralValue>> = Vec::new();
1817 if let Some(h) = t.headers_row() {
1818 out.extend(h.iter_rows());
1819 }
1820 if let Some(body) = t.data_body() {
1821 out.extend(body.iter_rows());
1822 }
1823 if let Some(tr) = t.totals_row() {
1824 out.extend(tr.iter_rows());
1825 }
1826 Ok(Box::new(InMemoryRange::new(out)))
1827 }
1828 Some(TableSpecifier::Data) => {
1829 if let Some(body) = t.data_body() {
1830 Ok(body)
1831 } else {
1832 Ok(Box::new(InMemoryRange::new(vec![])))
1833 }
1834 }
1835 Some(TableSpecifier::Combination(_)) => Err(ExcelError::new(
1837 ExcelErrorKind::NImpl,
1838 )
1839 .with_message("Complex structured references not yet supported".to_string())),
1840 Some(TableSpecifier::Row(_)) => Err(ExcelError::new(ExcelErrorKind::NImpl)
1841 .with_message("Row selectors (@/index) not yet supported".to_string())),
1842 Some(TableSpecifier::Headers) | Some(TableSpecifier::Totals) => {
1843 Err(ExcelError::new(ExcelErrorKind::NImpl).with_message(
1844 "Legacy Headers/Totals variants not used; use SpecialItem".to_string(),
1845 ))
1846 }
1847 None => Err(ExcelError::new(ExcelErrorKind::Ref).with_message(
1848 "Table reference without specifier is unsupported".to_string(),
1849 )),
1850 }
1851 }
1852 ReferenceType::NamedRange(n) => {
1853 let v = self.resolve_named_range_reference(n)?;
1854 Ok(Box::new(InMemoryRange::new(v)))
1855 }
1856 ReferenceType::Cell {
1857 sheet, row, col, ..
1858 } => {
1859 let v = self.resolve_cell_reference(sheet.as_deref(), *row, *col)?;
1860 Ok(Box::new(InMemoryRange::new(vec![vec![v]])))
1861 }
1862 ReferenceType::Cell3D { .. } | ReferenceType::Range3D { .. } => {
1863 Err(ExcelError::new(ExcelErrorKind::NImpl)
1864 .with_message("3D references are not yet supported".to_string()))
1865 }
1866 }
1867 }
1868}
1869
1870pub trait FunctionProvider: Send + Sync {
1873 fn get_function(&self, ns: &str, name: &str) -> Option<Arc<dyn Function>>;
1874
1875 #[doc(hidden)]
1876 fn get_function_for_planning(&self, _ns: &str, _name: &str) -> Option<Arc<dyn Function>> {
1877 None
1878 }
1879
1880 #[doc(hidden)]
1883 fn planning_semantic_revision(&self) -> Option<u64> {
1884 None
1885 }
1886
1887 #[doc(hidden)]
1888 fn function_capabilities(&self, ns: &str, name: &str) -> Option<crate::function::FnCaps> {
1889 self.get_function(ns, name).map(|function| function.caps())
1890 }
1891
1892 fn function_semantic_identity(
1893 &self,
1894 ns: &str,
1895 name: &str,
1896 arity: usize,
1897 ) -> Option<crate::function_contract::FunctionSemanticIdentity> {
1898 crate::function_registry::resolve_semantic_identity(self, ns, name, arity)
1899 }
1900}
1901
1902pub trait EvaluationContext: Resolver + FunctionProvider + SourceResolver {
1903 fn thread_pool(&self) -> Option<&Arc<rayon::ThreadPool>> {
1906 None
1907 }
1908
1909 fn cancellation_token(&self) -> Option<crate::engine::CancelToken> {
1916 None
1917 }
1918
1919 fn chunk_hint(&self) -> Option<usize> {
1921 None
1922 }
1923
1924 fn resolve_range_view<'c>(
1927 &'c self,
1928 _reference: &ReferenceType,
1929 _current_sheet: &str,
1930 ) -> Result<RangeView<'c>, ExcelError> {
1931 Err(ExcelError::new(ExcelErrorKind::NImpl))
1932 }
1933
1934 fn resolve_cell_reference_value(
1939 &self,
1940 sheet: Option<&str>,
1941 row: u32,
1942 col: u32,
1943 current_sheet: &str,
1944 ) -> Result<LiteralValue, ExcelError> {
1945 let reference = ReferenceType::Cell {
1946 sheet: sheet.map(str::to_string),
1947 row,
1948 col,
1949 row_abs: true,
1950 col_abs: true,
1951 };
1952 let view = self.resolve_range_view(&reference, current_sheet)?;
1953 Ok(view.as_1x1().unwrap_or(LiteralValue::Empty))
1954 }
1955
1956 fn resolve_cell_format(
1958 &self,
1959 _sheet: Option<&str>,
1960 _row: u32,
1961 _col: u32,
1962 _current_sheet: &str,
1963 ) -> Option<crate::format::FormatId> {
1964 None
1965 }
1966
1967 #[doc(hidden)]
1972 fn resolve_cell_reference_value_formatted(
1973 &self,
1974 sheet: Option<&str>,
1975 row: u32,
1976 col: u32,
1977 current_sheet: &str,
1978 ) -> Result<(LiteralValue, Option<crate::format::FormatId>), ExcelError> {
1979 let value = self.resolve_cell_reference_value(sheet, row, col, current_sheet)?;
1980 Ok((
1981 value,
1982 self.resolve_cell_format(sheet, row, col, current_sheet),
1983 ))
1984 }
1985
1986 fn format_class(
1988 &self,
1989 format: crate::format::FormatId,
1990 ) -> Option<formualizer_common::numfmt::FormatClass> {
1991 formualizer_common::numfmt::NumberFormat::builtin(format.0)
1992 .map(|format| format.class().clone())
1993 }
1994
1995 fn record_cell_derived_format(
1997 &self,
1998 _sheet: &str,
1999 _row: u32,
2000 _col: u32,
2001 _format: Option<crate::format::FormatId>,
2002 ) {
2003 }
2004
2005 fn locale(&self) -> crate::locale::Locale {
2007 crate::locale::Locale::invariant()
2008 }
2009
2010 fn workbook_sheet_count(&self) -> Option<usize> {
2012 None
2013 }
2014
2015 fn sheet_index_by_name(&self, _sheet: &str) -> Option<usize> {
2017 None
2018 }
2019
2020 fn current_sheet_index(&self, current_sheet: &str) -> Option<usize> {
2022 self.sheet_index_by_name(current_sheet)
2023 }
2024
2025 fn inspect_reference(
2027 &self,
2028 _reference: &ReferenceType,
2029 _current_sheet: &str,
2030 ) -> Result<Option<ReferenceInfo>, ExcelError> {
2031 Ok(None)
2032 }
2033
2034 fn formula_text_at_cell(&self, _cell: CellRef) -> Result<Option<String>, ExcelError> {
2036 Ok(None)
2037 }
2038
2039 fn resolve_spill_reference(
2052 &self,
2053 _anchor: &ReferenceType,
2054 _current_sheet: &str,
2055 ) -> Result<ReferenceType, ExcelError> {
2056 Err(ExcelError::new(ExcelErrorKind::Ref)
2057 .with_message("Spill references are not available in this context"))
2058 }
2059
2060 fn clock(&self) -> &dyn crate::timezone::ClockProvider {
2069 #[cfg(feature = "system-clock")]
2070 {
2071 static DEFAULT_CLOCK: std::sync::OnceLock<crate::timezone::SystemClock> =
2072 std::sync::OnceLock::new();
2073 DEFAULT_CLOCK.get_or_init(|| {
2074 crate::timezone::SystemClock::new(crate::timezone::TimeZoneSpec::default())
2075 })
2076 }
2077 #[cfg(not(feature = "system-clock"))]
2078 {
2079 static DEFAULT_CLOCK: std::sync::OnceLock<crate::timezone::FixedClock> =
2080 std::sync::OnceLock::new();
2081 DEFAULT_CLOCK.get_or_init(|| {
2082 crate::timezone::FixedClock::new(
2083 chrono::DateTime::UNIX_EPOCH,
2084 crate::timezone::TimeZoneSpec::Utc,
2085 )
2086 })
2087 }
2088 }
2089
2090 fn timezone(&self) -> &crate::timezone::TimeZoneSpec {
2094 self.clock().timezone()
2095 }
2096
2097 fn volatile_level(&self) -> VolatileLevel {
2099 VolatileLevel::Always
2100 }
2101
2102 fn workbook_seed(&self) -> u64 {
2104 0xF0F0_D0D0_AAAA_5555
2105 }
2106
2107 fn recalc_epoch(&self) -> u64 {
2109 0
2110 }
2111
2112 fn used_rows_for_columns(
2117 &self,
2118 _sheet: &str,
2119 _start_col: u32,
2120 _end_col: u32,
2121 ) -> Option<(u32, u32)> {
2122 None
2123 }
2124
2125 fn used_cols_for_rows(
2128 &self,
2129 _sheet: &str,
2130 _start_row: u32,
2131 _end_row: u32,
2132 ) -> Option<(u32, u32)> {
2133 None
2134 }
2135
2136 fn sheet_bounds(&self, _sheet: &str) -> Option<(u32, u32)> {
2138 None
2139 }
2140
2141 fn data_snapshot_id(&self) -> u64 {
2143 0
2144 }
2145
2146 fn backend_caps(&self) -> BackendCaps {
2148 BackendCaps::default()
2149 }
2150
2151 fn date_system(&self) -> crate::engine::DateSystem {
2156 crate::engine::DateSystem::Excel1900
2157 }
2158
2159 fn build_lookup_index(
2162 &self,
2163 _view: &RangeView<'_>,
2164 _axis: LookupAxis,
2165 ) -> Option<std::sync::Arc<LookupIndex>> {
2166 None
2167 }
2168
2169 fn build_criteria_mask(
2172 &self,
2173 _view: &RangeView<'_>,
2174 _col_in_view: usize,
2175 _pred: &crate::args::CriteriaPredicate,
2176 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2177 None
2178 }
2179
2180 fn build_row_visibility_mask(
2183 &self,
2184 _view: &RangeView<'_>,
2185 _mode: VisibilityMaskMode,
2186 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2187 None
2188 }
2189
2190 fn nested_subtotal_cells(
2197 &self,
2198 _view: &RangeView<'_>,
2199 _include_aggregate: bool,
2200 ) -> Option<Vec<(usize, usize, usize)>> {
2201 None
2202 }
2203}
2204
2205#[derive(Copy, Clone, Debug, Default)]
2207pub struct BackendCaps {
2208 pub streaming: bool,
2210 pub used_region: bool,
2212 pub write: bool,
2214 pub tables: bool,
2216 pub async_stream: bool,
2218}
2219
2220#[derive(Copy, Clone, Debug, Eq, PartialEq)]
2223pub enum VolatileLevel {
2224 Always,
2226 OnRecalc,
2228 OnOpen,
2230}
2231
2232pub trait FunctionContext<'ctx> {
2234 fn locale(&self) -> crate::locale::Locale;
2235 fn timezone(&self) -> &crate::timezone::TimeZoneSpec;
2236 fn clock(&self) -> &dyn crate::timezone::ClockProvider;
2237 fn thread_pool(&self) -> Option<&std::sync::Arc<rayon::ThreadPool>>;
2238 fn cancellation_token(&self) -> Option<crate::engine::CancelToken>;
2244 fn chunk_hint(&self) -> Option<usize>;
2245
2246 fn current_sheet(&self) -> &str;
2248
2249 fn workbook_sheet_count(&self) -> Option<usize> {
2250 None
2251 }
2252
2253 fn sheet_index_by_name(&self, _sheet: &str) -> Option<usize> {
2254 None
2255 }
2256
2257 fn current_sheet_index(&self) -> Option<usize> {
2258 self.sheet_index_by_name(self.current_sheet())
2259 }
2260
2261 fn inspect_reference(
2262 &self,
2263 _reference: &ReferenceType,
2264 ) -> Result<Option<ReferenceInfo>, ExcelError> {
2265 Ok(None)
2266 }
2267
2268 fn formula_text_at_cell(&self, _cell: CellRef) -> Result<Option<String>, ExcelError> {
2269 Ok(None)
2270 }
2271
2272 fn volatile_level(&self) -> VolatileLevel;
2273 fn workbook_seed(&self) -> u64;
2274 fn recalc_epoch(&self) -> u64;
2275 fn current_cell(&self) -> Option<CellRef>;
2276
2277 fn resolve_range_view(
2279 &self,
2280 _reference: &ReferenceType,
2281 _current_sheet: &str,
2282 ) -> Result<RangeView<'ctx>, ExcelError>;
2283
2284 fn rng_for_current(&self, fn_salt: u64) -> rand::rngs::SmallRng {
2288 use crate::rng::{compose_seed, small_rng_from_lanes};
2289 let (sheet_id, row, col) = self
2290 .current_cell()
2291 .map(|c| (c.sheet_id as u32, c.coord.row(), c.coord.col()))
2292 .unwrap_or((0, 0, 0));
2293 let epoch = match self.volatile_level() {
2295 VolatileLevel::OnRecalc => self.recalc_epoch(),
2296 _ => 0,
2297 };
2298 let (l0, l1) = compose_seed(self.workbook_seed(), sheet_id, row, col, fn_salt, epoch);
2299 small_rng_from_lanes(l0, l1)
2300 }
2301
2302 fn date_system(&self) -> crate::engine::DateSystem {
2304 crate::engine::DateSystem::Excel1900
2305 }
2306
2307 fn get_lookup_index(
2310 &self,
2311 _view: &RangeView<'_>,
2312 _axis: LookupAxis,
2313 ) -> Option<std::sync::Arc<LookupIndex>> {
2314 None
2315 }
2316
2317 fn get_criteria_mask(
2320 &self,
2321 _view: &RangeView<'_>,
2322 _col_in_view: usize,
2323 _pred: &crate::args::CriteriaPredicate,
2324 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2325 None
2326 }
2327
2328 fn get_row_visibility_mask(
2330 &self,
2331 _view: &RangeView<'_>,
2332 _mode: VisibilityMaskMode,
2333 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2334 None
2335 }
2336
2337 fn get_nested_subtotal_cells(
2341 &self,
2342 _view: &RangeView<'_>,
2343 _include_aggregate: bool,
2344 ) -> Option<Vec<(usize, usize, usize)>> {
2345 None
2346 }
2347}
2348
2349pub struct DefaultFunctionContext<'a> {
2351 pub base: &'a dyn EvaluationContext,
2352 pub current: Option<CellRef>,
2353 pub current_sheet: &'a str,
2354}
2355
2356impl<'a> DefaultFunctionContext<'a> {
2357 pub fn new(
2358 base: &'a dyn EvaluationContext,
2359 current: Option<CellRef>,
2360 current_sheet: &'a str,
2361 ) -> Self {
2362 Self {
2363 base,
2364 current,
2365 current_sheet,
2366 }
2367 }
2368
2369 pub fn new_with_sheet(
2370 base: &'a dyn EvaluationContext,
2371 current: Option<CellRef>,
2372 current_sheet: &'a str,
2373 ) -> Self {
2374 Self::new(base, current, current_sheet)
2375 }
2376}
2377
2378impl<'a> FunctionContext<'a> for DefaultFunctionContext<'a> {
2379 fn locale(&self) -> crate::locale::Locale {
2380 self.base.locale()
2381 }
2382
2383 fn current_sheet(&self) -> &str {
2384 self.current_sheet
2385 }
2386
2387 fn workbook_sheet_count(&self) -> Option<usize> {
2388 self.base.workbook_sheet_count()
2389 }
2390
2391 fn sheet_index_by_name(&self, sheet: &str) -> Option<usize> {
2392 self.base.sheet_index_by_name(sheet)
2393 }
2394
2395 fn current_sheet_index(&self) -> Option<usize> {
2396 self.base.current_sheet_index(self.current_sheet)
2397 }
2398
2399 fn inspect_reference(
2400 &self,
2401 reference: &ReferenceType,
2402 ) -> Result<Option<ReferenceInfo>, ExcelError> {
2403 self.base.inspect_reference(reference, self.current_sheet)
2404 }
2405
2406 fn formula_text_at_cell(&self, cell: CellRef) -> Result<Option<String>, ExcelError> {
2407 self.base.formula_text_at_cell(cell)
2408 }
2409
2410 fn timezone(&self) -> &crate::timezone::TimeZoneSpec {
2411 self.base.timezone()
2412 }
2413
2414 fn clock(&self) -> &dyn crate::timezone::ClockProvider {
2415 self.base.clock()
2416 }
2417 fn thread_pool(&self) -> Option<&std::sync::Arc<rayon::ThreadPool>> {
2418 self.base.thread_pool()
2419 }
2420 fn cancellation_token(&self) -> Option<crate::engine::CancelToken> {
2421 self.base.cancellation_token()
2422 }
2423 fn chunk_hint(&self) -> Option<usize> {
2424 self.base.chunk_hint()
2425 }
2426
2427 fn volatile_level(&self) -> VolatileLevel {
2428 self.base.volatile_level()
2429 }
2430 fn workbook_seed(&self) -> u64 {
2431 self.base.workbook_seed()
2432 }
2433 fn recalc_epoch(&self) -> u64 {
2434 self.base.recalc_epoch()
2435 }
2436 fn current_cell(&self) -> Option<CellRef> {
2437 self.current
2438 }
2439
2440 fn resolve_range_view(
2441 &self,
2442 reference: &ReferenceType,
2443 current_sheet: &str,
2444 ) -> Result<RangeView<'a>, ExcelError> {
2445 self.base.resolve_range_view(reference, current_sheet)
2446 }
2447
2448 fn date_system(&self) -> crate::engine::DateSystem {
2451 self.base.date_system()
2452 }
2453
2454 fn get_lookup_index(
2455 &self,
2456 view: &RangeView<'_>,
2457 axis: LookupAxis,
2458 ) -> Option<std::sync::Arc<LookupIndex>> {
2459 self.base.build_lookup_index(view, axis)
2460 }
2461
2462 fn get_criteria_mask(
2463 &self,
2464 view: &RangeView<'_>,
2465 col_in_view: usize,
2466 pred: &crate::args::CriteriaPredicate,
2467 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2468 self.base.build_criteria_mask(view, col_in_view, pred)
2469 }
2470
2471 fn get_row_visibility_mask(
2472 &self,
2473 view: &RangeView<'_>,
2474 mode: VisibilityMaskMode,
2475 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2476 self.base.build_row_visibility_mask(view, mode)
2477 }
2478
2479 fn get_nested_subtotal_cells(
2480 &self,
2481 view: &RangeView<'_>,
2482 include_aggregate: bool,
2483 ) -> Option<Vec<(usize, usize, usize)>> {
2484 self.base.nested_subtotal_cells(view, include_aggregate)
2485 }
2486}