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
107#[derive(Clone)]
108pub enum CalcValue<'a> {
109 Scalar(LiteralValue),
110 Range(RangeView<'a>),
111 Callable(Arc<dyn CustomCallable>),
112}
113
114#[derive(Clone)]
120pub(crate) enum ResolvedArgument<'a> {
121 Range(RangeView<'a>),
122 ReferenceError(ExcelError),
123 Value(CalcValue<'a>),
124}
125
126impl std::fmt::Debug for ResolvedArgument<'_> {
127 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
128 match self {
129 Self::Range(view) => f.debug_tuple("Range").field(view).finish(),
130 Self::ReferenceError(error) => f.debug_tuple("ReferenceError").field(error).finish(),
131 Self::Value(value) => f.debug_tuple("Value").field(value).finish(),
132 }
133 }
134}
135
136impl<'a> std::fmt::Debug for CalcValue<'a> {
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 match self {
139 CalcValue::Scalar(v) => f.debug_tuple("Scalar").field(v).finish(),
140 CalcValue::Range(rv) => {
141 let (r, c) = rv.dims();
142 f.debug_tuple("Range").field(&(r, c)).finish()
143 }
144 CalcValue::Callable(_) => f.write_str("Callable(<opaque>)"),
145 }
146 }
147}
148
149impl<'a> CalcValue<'a> {
150 pub fn into_literal(self) -> LiteralValue {
151 match self {
152 CalcValue::Scalar(s) => s,
153 CalcValue::Range(rv) => {
154 let (rows, cols) = rv.dims();
155 if rows == 1 && cols == 1 {
156 rv.get_cell(0, 0)
157 } else {
158 let mut data = Vec::with_capacity(rows);
159 for row_idx in 0..rows {
160 let mut row = Vec::with_capacity(cols);
161 for col_idx in 0..cols {
162 row.push(rv.get_cell(row_idx, col_idx));
163 }
164 data.push(row);
165 }
166 LiteralValue::Array(data)
167 }
168 }
169 CalcValue::Callable(_) => LiteralValue::Error(
170 ExcelError::new(ExcelErrorKind::Calc).with_message("LAMBDA value must be invoked"),
171 ),
172 }
173 }
174
175 pub fn as_scalar(&self) -> Option<&LiteralValue> {
176 match self {
177 CalcValue::Scalar(s) => Some(s),
178 _ => None,
179 }
180 }
181
182 pub fn as_range(&self) -> Option<&RangeView<'a>> {
183 match self {
184 CalcValue::Range(r) => Some(r),
185 _ => None,
186 }
187 }
188
189 pub fn as_callable(&self) -> Option<&Arc<dyn CustomCallable>> {
190 match self {
191 CalcValue::Callable(c) => Some(c),
192 _ => None,
193 }
194 }
195
196 pub fn into_owned(self) -> LiteralValue {
197 self.into_literal()
198 }
199}
200
201impl From<CalcValue<'_>> for LiteralValue {
202 fn from(val: CalcValue<'_>) -> Self {
203 val.into_literal()
204 }
205}
206
207impl<'a> PartialEq<LiteralValue> for CalcValue<'a> {
208 fn eq(&self, other: &LiteralValue) -> bool {
209 match self {
210 CalcValue::Scalar(s) => s == other,
211 CalcValue::Range(rv) => match other {
212 LiteralValue::Array(arr) => {
213 let (rows, cols) = rv.dims();
214 if arr.len() != rows {
215 return false;
216 }
217 for (r, row) in arr.iter().enumerate() {
218 if row.len() != cols {
219 return false;
220 }
221 for (c, cell) in row.iter().enumerate() {
222 if &rv.get_cell(r, c) != cell {
223 return false;
224 }
225 }
226 }
227 true
228 }
229 _ => {
230 let (rows, cols) = rv.dims();
231 rows == 1 && cols == 1 && &rv.get_cell(0, 0) == other
232 }
233 },
234 CalcValue::Callable(_) => false,
235 }
236 }
237}
238
239impl<'a> PartialEq<CalcValue<'a>> for LiteralValue {
240 fn eq(&self, other: &CalcValue<'a>) -> bool {
241 other == self
242 }
243}
244
245pub enum EvaluatedArg<'a> {
246 LiteralValue(CowValue<'a>),
247 Range(Box<dyn Range>),
248}
249
250enum ArgumentExpr<'a> {
251 Ast(&'a ASTNode),
252 Arena {
253 id: crate::engine::arena::AstNodeId,
254 data_store: &'a crate::engine::arena::DataStore,
255 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
256 },
257}
258
259pub struct ArgumentHandle<'a, 'b> {
260 expr: ArgumentExpr<'a>,
261 interp: &'a Interpreter<'b>,
262 cached_ast: std::cell::OnceCell<ASTNode>,
263 cached_ref: std::cell::OnceCell<ReferenceType>,
264 cached_resolved: std::cell::OnceCell<Result<ResolvedArgument<'b>, ExcelError>>,
265 cached_value: std::cell::OnceCell<Result<crate::traits::CalcValue<'b>, ExcelError>>,
274}
275
276impl<'a, 'b> ArgumentHandle<'a, 'b> {
277 pub(crate) fn new(node: &'a ASTNode, interp: &'a Interpreter<'b>) -> Self {
278 Self {
279 expr: ArgumentExpr::Ast(node),
280 interp,
281 cached_ast: std::cell::OnceCell::new(),
282 cached_ref: std::cell::OnceCell::new(),
283 cached_resolved: std::cell::OnceCell::new(),
284 cached_value: std::cell::OnceCell::new(),
285 }
286 }
287
288 pub(crate) fn new_arena(
289 id: crate::engine::arena::AstNodeId,
290 interp: &'a Interpreter<'b>,
291 data_store: &'a crate::engine::arena::DataStore,
292 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
293 ) -> Self {
294 Self {
295 expr: ArgumentExpr::Arena {
296 id,
297 data_store,
298 sheet_registry,
299 },
300 interp,
301 cached_ast: std::cell::OnceCell::new(),
302 cached_ref: std::cell::OnceCell::new(),
303 cached_resolved: std::cell::OnceCell::new(),
304 cached_value: std::cell::OnceCell::new(),
305 }
306 }
307
308 pub fn is_omitted(&self) -> bool {
312 match &self.expr {
313 ArgumentExpr::Ast(node) => matches!(node.node_type, ASTNodeType::Omitted),
314 ArgumentExpr::Arena { id, data_store, .. } => matches!(
315 data_store.get_node(*id),
316 Some(crate::engine::arena::AstNodeData::Omitted)
317 ),
318 }
319 }
320
321 pub(crate) fn has_reference_semantics(&self) -> bool {
327 self.reference_attempt().is_some()
328 }
329
330 pub fn value(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
331 self.cached_value
332 .get_or_init(|| self.compute_value())
333 .clone()
334 }
335
336 pub(crate) fn value_for_text(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
342 if self.is_omitted() {
343 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(
344 String::new(),
345 )))
346 } else {
347 self.value()
348 }
349 }
350
351 pub(crate) fn resolve_once_for_text(&self) -> Result<ResolvedArgument<'b>, ExcelError> {
352 if self.is_omitted() {
353 Ok(ResolvedArgument::Value(crate::traits::CalcValue::Scalar(
354 LiteralValue::Text(String::new()),
355 )))
356 } else {
357 self.resolve_once()
358 }
359 }
360
361 fn compute_value(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
362 match &self.expr {
363 ArgumentExpr::Ast(node) => match &node.node_type {
364 ASTNodeType::Literal(v) => Ok(crate::traits::CalcValue::Scalar(v.clone())),
365 ASTNodeType::Omitted => {
368 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
369 }
370 _ => self.interp.evaluate_ast(node),
371 },
372 ArgumentExpr::Arena {
373 id,
374 data_store,
375 sheet_registry,
376 } => {
377 if matches!(
378 data_store.get_node(*id),
379 Some(crate::engine::arena::AstNodeData::Omitted)
380 ) {
381 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
382 } else {
383 self.interp
384 .evaluate_arena_ast(*id, data_store, sheet_registry)
385 }
386 }
387 }
388 }
389
390 pub fn value_with_env(
391 &self,
392 env: crate::interpreter::LocalEnv,
393 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
394 let scoped = self.interp.with_local_env(env);
395 match &self.expr {
396 ArgumentExpr::Ast(node) => match &node.node_type {
397 ASTNodeType::Literal(v) => Ok(crate::traits::CalcValue::Scalar(v.clone())),
398 ASTNodeType::Omitted => {
399 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
400 }
401 _ => scoped.evaluate_ast(node),
402 },
403 ArgumentExpr::Arena {
404 id,
405 data_store,
406 sheet_registry,
407 } => {
408 if matches!(
409 data_store.get_node(*id),
410 Some(crate::engine::arena::AstNodeData::Omitted)
411 ) {
412 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
413 } else {
414 scoped.evaluate_arena_ast(*id, data_store, sheet_registry)
415 }
416 }
417 }
418 }
419
420 pub fn current_env(&self) -> crate::interpreter::LocalEnv {
421 self.interp.local_env().clone()
422 }
423
424 pub fn inline_array_literal(&self) -> Result<Option<Vec<Vec<LiteralValue>>>, ExcelError> {
425 match &self.expr {
426 ArgumentExpr::Ast(node) => match &node.node_type {
427 ASTNodeType::Literal(LiteralValue::Array(arr)) => Ok(Some(arr.clone())),
428 _ => Ok(None),
429 },
430 ArgumentExpr::Arena {
431 id,
432 data_store,
433 sheet_registry,
434 } => {
435 let node = data_store.get_node(*id).ok_or_else(|| {
436 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
437 })?;
438 match node {
439 crate::engine::arena::AstNodeData::Literal(vref) => {
440 match data_store.retrieve_value(*vref) {
441 LiteralValue::Array(arr) => Ok(Some(arr)),
442 _ => Ok(None),
443 }
444 }
445 _ => {
446 let _ = sheet_registry;
449 Ok(None)
450 }
451 }
452 }
453 }
454 }
455
456 fn reference_for_eval(&self) -> Result<ReferenceType, ExcelError> {
457 match &self.expr {
458 ArgumentExpr::Ast(node) => match &node.node_type {
459 ASTNodeType::Reference { reference, .. } => {
460 self.interp.reference_for_current_offset(reference)
461 }
462 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
463 self.interp.evaluate_ast_as_reference(node)
464 }
465 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
466 .with_message("Expected a reference (by-ref argument)")),
467 },
468 ArgumentExpr::Arena {
469 id,
470 data_store,
471 sheet_registry,
472 } => {
473 let node = data_store.get_node(*id).ok_or_else(|| {
474 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
475 })?;
476 match node {
477 crate::engine::arena::AstNodeData::Reference { ref_type, .. } => {
478 let reference = data_store
479 .reconstruct_reference_type_for_eval(ref_type, sheet_registry);
480 self.interp.reference_for_current_offset(&reference)
481 }
482 crate::engine::arena::AstNodeData::Function { .. }
483 | crate::engine::arena::AstNodeData::BinaryOp { .. } => self
484 .interp
485 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry),
486 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
487 .with_message("Expected a reference (by-ref argument)")),
488 }
489 }
490 }
491 }
492
493 fn reference_attempt(&self) -> Option<Result<ReferenceType, ExcelError>> {
494 match &self.expr {
495 ArgumentExpr::Ast(node) => match &node.node_type {
496 ASTNodeType::Reference { reference, .. } => {
497 Some(self.interp.reference_for_current_offset(reference))
498 }
499 ASTNodeType::BinaryOp { op, .. } if op == ":" => {
500 Some(self.interp.evaluate_ast_as_reference(node))
501 }
502 ASTNodeType::Function { name, .. }
503 if self
504 .interp
505 .context
506 .function_capabilities("", name)
507 .is_some_and(|caps| {
508 caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)
509 }) =>
510 {
511 self.interp.try_evaluate_ast_as_reference(node)
512 }
513 _ => None,
514 },
515 ArgumentExpr::Arena {
516 id,
517 data_store,
518 sheet_registry,
519 } => {
520 let node = match data_store.get_node(*id) {
521 Some(node) => node,
522 None => {
523 return Some(Err(
524 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
525 ));
526 }
527 };
528 match node {
529 crate::engine::arena::AstNodeData::Reference { ref_type, .. } => {
530 let reference = data_store
531 .reconstruct_reference_type_for_eval(ref_type, sheet_registry);
532 Some(self.interp.reference_for_current_offset(&reference))
533 }
534 crate::engine::arena::AstNodeData::BinaryOp { op_id, .. }
535 if data_store.resolve_ast_string(*op_id) == ":" =>
536 {
537 Some(self.interp.evaluate_arena_ast_as_reference(
538 *id,
539 data_store,
540 sheet_registry,
541 ))
542 }
543 crate::engine::arena::AstNodeData::Function { name_id, .. } => {
544 let name = data_store.resolve_ast_string(*name_id);
545 if self
546 .interp
547 .context
548 .function_capabilities("", name)
549 .is_some_and(|caps| {
550 caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)
551 })
552 {
553 self.interp.try_evaluate_arena_ast_as_reference(
554 *id,
555 data_store,
556 sheet_registry,
557 )
558 } else {
559 None
560 }
561 }
562 _ => None,
563 }
564 }
565 }
566 }
567
568 pub(crate) fn resolve_once(&self) -> Result<ResolvedArgument<'b>, ExcelError> {
574 self.cached_resolved
575 .get_or_init(|| self.compute_resolved_argument())
576 .clone()
577 }
578
579 fn with_context_cancel_token(&self, view: RangeView<'b>) -> RangeView<'b> {
580 match self.interp.context.cancellation_token() {
581 Some(token) => view.with_cancel_token(Some(token)),
582 None => view,
583 }
584 }
585
586 fn compute_resolved_argument(&self) -> Result<ResolvedArgument<'b>, ExcelError> {
587 if let Some(attempt) = self.reference_attempt() {
588 let reference = match attempt {
589 Ok(reference) => reference,
590 Err(error) if error.kind == ExcelErrorKind::Cancelled => return Err(error),
591 Err(error) => return Ok(ResolvedArgument::ReferenceError(error)),
592 };
593 return match self
594 .interp
595 .context
596 .resolve_range_view(&reference, self.interp.current_sheet())
597 {
598 Ok(view) => Ok(ResolvedArgument::Range(
599 self.with_context_cancel_token(view),
600 )),
601 Err(error) if error.kind == ExcelErrorKind::Cancelled => Err(error),
602 Err(error) => Ok(ResolvedArgument::ReferenceError(error)),
603 };
604 }
605
606 match self.value()? {
607 CalcValue::Range(view) => Ok(ResolvedArgument::Range(
608 self.with_context_cancel_token(view),
609 )),
610 CalcValue::Scalar(LiteralValue::Array(rows)) => {
611 let view = RangeView::try_from_owned_rows(
612 rows,
613 self.interp.context.date_system(),
614 self.interp.context.cancellation_token(),
615 )?;
616 Ok(ResolvedArgument::Range(view))
617 }
618 other => Ok(ResolvedArgument::Value(other)),
619 }
620 }
621
622 pub fn range(&self) -> Result<Box<dyn Range>, ExcelError> {
623 match &self.expr {
624 ArgumentExpr::Ast(node) => match &node.node_type {
625 ASTNodeType::Reference { reference, .. } => {
626 let reference = self.interp.reference_for_current_offset(reference)?;
628 let view = self
629 .interp
630 .context
631 .resolve_range_view(&reference, self.interp.current_sheet())?;
632 let (rows, cols) = view.dims();
633 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
634 view.for_each_row(&mut |row| {
635 let row_data: Vec<LiteralValue> = (0..cols)
636 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
637 .collect();
638 out.push(row_data);
639 Ok(())
640 })?;
641 Ok(Box::new(InMemoryRange::new(out)))
642 }
643 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
644 let reference = self.reference_for_eval()?;
645 let view = self
646 .interp
647 .context
648 .resolve_range_view(&reference, self.interp.current_sheet())?;
649 let (rows, cols) = view.dims();
650 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
651 view.for_each_row(&mut |row| {
652 let row_data: Vec<LiteralValue> = (0..cols)
653 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
654 .collect();
655 out.push(row_data);
656 Ok(())
657 })?;
658 Ok(Box::new(InMemoryRange::new(out)))
659 }
660 ASTNodeType::Array(rows) => {
661 let mut materialized = Vec::new();
662 for row in rows {
663 let mut materialized_row = Vec::new();
664 for cell in row {
665 materialized_row.push(self.interp.evaluate_ast(cell)?.into_literal());
666 }
667 materialized.push(materialized_row);
668 }
669 Ok(Box::new(InMemoryRange::new(materialized)))
670 }
671 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
672 .with_message(format!("Expected a range, got {:?}", node.node_type))),
673 },
674 ArgumentExpr::Arena { id, data_store, .. } => {
675 let node = data_store.get_node(*id).ok_or_else(|| {
676 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
677 })?;
678
679 match node {
680 crate::engine::arena::AstNodeData::Reference { .. }
681 | crate::engine::arena::AstNodeData::Function { .. }
682 | crate::engine::arena::AstNodeData::BinaryOp { .. } => {
683 let reference = self.reference_for_eval()?;
684 let view = self
685 .interp
686 .context
687 .resolve_range_view(&reference, self.interp.current_sheet())?;
688 let (rows, cols) = view.dims();
689 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
690 view.for_each_row(&mut |row| {
691 let row_data: Vec<LiteralValue> = (0..cols)
692 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
693 .collect();
694 out.push(row_data);
695 Ok(())
696 })?;
697 Ok(Box::new(InMemoryRange::new(out)))
698 }
699 crate::engine::arena::AstNodeData::Array { .. } => {
700 let (rows, cols, elements) =
701 data_store.get_array_elems(*id).ok_or_else(|| {
702 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
703 })?;
704 let rows_usize = rows as usize;
705 let cols_usize = cols as usize;
706 let mut materialized: Vec<Vec<LiteralValue>> =
707 Vec::with_capacity(rows_usize);
708 for r in 0..rows_usize {
709 let mut row = Vec::with_capacity(cols_usize);
710 for c in 0..cols_usize {
711 let idx = r * cols_usize + c;
712 let elem_id = elements.get(idx).copied().ok_or_else(|| {
713 ExcelError::new(ExcelErrorKind::Value)
714 .with_message("Invalid array")
715 })?;
716 let v = self.interp.evaluate_arena_ast(
717 elem_id,
718 data_store,
719 self.sheet_registry(),
720 )?;
721 row.push(v.into_literal());
722 }
723 materialized.push(row);
724 }
725 Ok(Box::new(InMemoryRange::new(materialized)))
726 }
727 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
728 .with_message("Argument cannot be interpreted as a range.")),
729 }
730 }
731 }
732 }
733
734 fn sheet_registry(&self) -> &crate::engine::sheet_registry::SheetRegistry {
735 match &self.expr {
736 ArgumentExpr::Ast(_) => {
737 unreachable!("sheet_registry only used for arena ArgumentHandle")
739 }
740 ArgumentExpr::Arena { sheet_registry, .. } => sheet_registry,
741 }
742 }
743
744 pub fn range_view(&self) -> Result<RangeView<'b>, ExcelError> {
752 match self.resolve_once()? {
753 ResolvedArgument::Range(view) => Ok(view),
754 ResolvedArgument::ReferenceError(error) => Err(error),
757 ResolvedArgument::Value(CalcValue::Range(view)) => {
762 Ok(self.with_context_cancel_token(view))
763 }
764 ResolvedArgument::Value(CalcValue::Scalar(LiteralValue::Array(rows))) => {
765 RangeView::try_from_owned_rows(
766 rows,
767 self.interp.context.date_system(),
768 self.interp.context.cancellation_token(),
769 )
770 }
771 ResolvedArgument::Value(_) => Err(ExcelError::new(ExcelErrorKind::Ref)
772 .with_message("Argument cannot be interpreted as a range.")),
773 }
774 }
775
776 pub fn range_view_or_scalar(&self) -> Result<RangeView<'b>, ExcelError> {
796 match self.resolve_once()? {
797 ResolvedArgument::Range(view) => Ok(view),
798 ResolvedArgument::ReferenceError(error) => Err(error),
799 ResolvedArgument::Value(CalcValue::Range(view)) => {
800 Ok(self.with_context_cancel_token(view))
801 }
802 ResolvedArgument::Value(CalcValue::Scalar(LiteralValue::Array(rows))) => {
803 RangeView::try_from_owned_rows(
804 rows,
805 self.interp.context.date_system(),
806 self.interp.context.cancellation_token(),
807 )
808 }
809 ResolvedArgument::Value(CalcValue::Scalar(LiteralValue::Error(error))) => Err(error),
812 ResolvedArgument::Value(CalcValue::Scalar(scalar)) => RangeView::try_from_owned_rows(
813 vec![vec![scalar]],
814 self.interp.context.date_system(),
815 self.interp.context.cancellation_token(),
816 ),
817 ResolvedArgument::Value(CalcValue::Callable(_)) => {
819 Err(ExcelError::new(ExcelErrorKind::Ref)
820 .with_message("Argument cannot be interpreted as a range."))
821 }
822 }
823 }
824
825 pub fn value_or_range(&self) -> Result<EvaluatedArg<'_>, ExcelError> {
826 self.range().map(EvaluatedArg::Range).or_else(|_| {
827 self.value()
828 .map(|cv| EvaluatedArg::LiteralValue(Cow::Owned(cv.into_literal())))
829 })
830 }
831
832 pub fn lazy_values_owned(
837 &'a self,
838 ) -> Result<Box<dyn Iterator<Item = LiteralValue> + 'a>, ExcelError> {
839 match &self.expr {
840 ArgumentExpr::Ast(node) => match &node.node_type {
841 ASTNodeType::Reference { .. } => {
842 let view = self.range_view()?;
843 let mut values: Vec<LiteralValue> = Vec::new();
844 view.for_each_cell(&mut |v| {
845 values.push(v.clone());
846 Ok(())
847 })?;
848 Ok(Box::new(values.into_iter()))
849 }
850 ASTNodeType::Array(rows) => {
851 struct ArrayEvalIter<'a, 'b> {
852 rows: &'a [Vec<ASTNode>],
853 r: usize,
854 c: usize,
855 interp: &'a Interpreter<'b>,
856 }
857 impl<'a, 'b> Iterator for ArrayEvalIter<'a, 'b> {
858 type Item = LiteralValue;
859 fn next(&mut self) -> Option<Self::Item> {
860 if self.rows.is_empty() {
861 return None;
862 }
863 let rows = self.rows;
864 let mut r = self.r;
865 let mut c = self.c;
866 if r >= rows.len() {
867 return None;
868 }
869 let node = &rows[r][c];
870 c += 1;
872 if c >= rows[r].len() {
873 r += 1;
874 c = 0;
875 }
876 self.r = r;
877 self.c = c;
878 match self.interp.evaluate_ast(node) {
879 Ok(cv) => Some(cv.into_literal()),
880 Err(e) => Some(LiteralValue::Error(e)),
881 }
882 }
883 }
884 let it = ArrayEvalIter {
885 rows,
886 r: 0,
887 c: 0,
888 interp: self.interp,
889 };
890 Ok(Box::new(it))
891 }
892 _ => {
893 let v = self.value()?.into_literal();
895 Ok(Box::new(std::iter::once(v)))
896 }
897 },
898 ArgumentExpr::Arena {
899 id,
900 data_store,
901 sheet_registry,
902 } => {
903 let node = data_store.get_node(*id).ok_or_else(|| {
904 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
905 })?;
906
907 match node {
908 crate::engine::arena::AstNodeData::Reference { .. } => {
909 let view = self.range_view()?;
910 let mut values: Vec<LiteralValue> = Vec::new();
911 view.for_each_cell(&mut |v| {
912 values.push(v.clone());
913 Ok(())
914 })?;
915 Ok(Box::new(values.into_iter()))
916 }
917 crate::engine::arena::AstNodeData::Array { .. } => {
918 let (rows, cols, elements) =
919 data_store.get_array_elems(*id).ok_or_else(|| {
920 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
921 })?;
922
923 struct ArenaArrayEvalIter<'a, 'b> {
924 elements: &'a [crate::engine::arena::AstNodeId],
925 idx: usize,
926 interp: &'a Interpreter<'b>,
927 data_store: &'a crate::engine::arena::DataStore,
928 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
929 }
930
931 impl<'a, 'b> Iterator for ArenaArrayEvalIter<'a, 'b> {
932 type Item = LiteralValue;
933
934 fn next(&mut self) -> Option<Self::Item> {
935 let id = self.elements.get(self.idx).copied()?;
936 self.idx += 1;
937 match self.interp.evaluate_arena_ast(
938 id,
939 self.data_store,
940 self.sheet_registry,
941 ) {
942 Ok(cv) => Some(cv.into_literal()),
943 Err(e) => Some(LiteralValue::Error(e)),
944 }
945 }
946 }
947
948 let _ = (rows, cols);
949 let it = ArenaArrayEvalIter {
950 elements,
951 idx: 0,
952 interp: self.interp,
953 data_store,
954 sheet_registry,
955 };
956 Ok(Box::new(it))
957 }
958 _ => {
959 let v = self
960 .interp
961 .evaluate_arena_ast(*id, data_store, sheet_registry)?;
962 Ok(Box::new(std::iter::once(v.into_literal())))
963 }
964 }
965 }
966 }
967 }
968
969 pub fn ast(&self) -> &ASTNode {
970 match &self.expr {
971 ArgumentExpr::Ast(node) => node,
972 ArgumentExpr::Arena {
973 id,
974 data_store,
975 sheet_registry,
976 } => self.cached_ast.get_or_init(|| {
977 data_store
978 .retrieve_ast(*id, sheet_registry)
979 .unwrap_or_else(|| ASTNode {
980 node_type: ASTNodeType::Literal(LiteralValue::Error(
981 ExcelError::new(ExcelErrorKind::Value)
982 .with_message("Missing formula AST"),
983 )),
984 source_token: None,
985 contains_volatile: false,
986 })
987 }),
988 }
989 }
990
991 pub fn as_reference(&self) -> Result<&ReferenceType, ExcelError> {
994 match &self.expr {
995 ArgumentExpr::Ast(node) => match &node.node_type {
996 ASTNodeType::Reference { reference, .. } => Ok(reference),
997 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
998 .with_message("Expected a reference (by-ref argument)")),
999 },
1000 ArgumentExpr::Arena { .. } => {
1001 let reference = self.reference_for_eval()?;
1002 Ok(self.cached_ref.get_or_init(|| reference))
1003 }
1004 }
1005 }
1006
1007 pub fn as_reference_or_eval(&self) -> Result<ReferenceType, ExcelError> {
1010 match &self.expr {
1011 ArgumentExpr::Ast(node) => match &node.node_type {
1012 ASTNodeType::Reference { reference, .. } => {
1013 self.interp.reference_for_current_offset(reference)
1014 }
1015 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
1016 self.interp.evaluate_ast_as_reference(node)
1017 }
1018 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1019 .with_message("Argument is not a reference")),
1020 },
1021 ArgumentExpr::Arena {
1022 id,
1023 data_store,
1024 sheet_registry,
1025 } => {
1026 let node = data_store.get_node(*id).ok_or_else(|| {
1027 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
1028 })?;
1029
1030 match node {
1031 crate::engine::arena::AstNodeData::Reference { .. } => {
1032 self.reference_for_eval()
1033 }
1034 crate::engine::arena::AstNodeData::Function { .. }
1035 | crate::engine::arena::AstNodeData::BinaryOp { .. } => self
1036 .interp
1037 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry),
1038 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1039 .with_message("Argument is not a reference")),
1040 }
1041 }
1042 }
1043 }
1044
1045 pub fn matches_kind(&self, k: formualizer_common::ArgKind) -> Result<bool, ExcelError> {
1047 Ok(match k {
1048 formualizer_common::ArgKind::Any => true,
1049 formualizer_common::ArgKind::Range => self.range().is_ok(),
1050 formualizer_common::ArgKind::Number => matches!(
1051 self.value()?.into_literal(),
1052 LiteralValue::Number(_) | LiteralValue::Int(_)
1053 ),
1054 formualizer_common::ArgKind::Text => {
1055 matches!(self.value()?.into_literal(), LiteralValue::Text(_))
1056 }
1057 formualizer_common::ArgKind::Logical => {
1058 matches!(self.value()?.into_literal(), LiteralValue::Boolean(_))
1059 }
1060 })
1061 }
1062}
1063
1064#[derive(Debug, Clone)]
1066pub struct InMemoryRange {
1067 data: Vec<Vec<LiteralValue>>,
1068}
1069impl InMemoryRange {
1070 pub fn new(d: Vec<Vec<LiteralValue>>) -> Self {
1071 Self { data: d }
1072 }
1073}
1074impl Range for InMemoryRange {
1075 fn get(&self, r: usize, c: usize) -> Result<LiteralValue, ExcelError> {
1076 Ok(self
1077 .data
1078 .get(r)
1079 .and_then(|row| row.get(c))
1080 .cloned()
1081 .unwrap_or(LiteralValue::Empty))
1082 }
1083 fn dimensions(&self) -> (usize, usize) {
1084 (self.data.len(), self.data.first().map_or(0, |r| r.len()))
1085 }
1086 fn as_any(&self) -> &dyn Any {
1087 self
1088 }
1089}
1090
1091pub trait Table: Debug + Send + Sync {
1094 fn get_cell(&self, row: usize, column: &str) -> Result<LiteralValue, ExcelError>;
1095 fn get_column(&self, column: &str) -> Result<Box<dyn Range>, ExcelError>;
1096 fn columns(&self) -> Vec<String> {
1098 vec![]
1099 }
1100 fn data_height(&self) -> usize {
1102 0
1103 }
1104 fn has_headers(&self) -> bool {
1106 false
1107 }
1108 fn has_totals(&self) -> bool {
1110 false
1111 }
1112 fn headers_row(&self) -> Option<Box<dyn Range>> {
1114 None
1115 }
1116 fn totals_row(&self) -> Option<Box<dyn Range>> {
1118 None
1119 }
1120 fn data_body(&self) -> Option<Box<dyn Range>> {
1122 None
1123 }
1124 fn clone_box(&self) -> Box<dyn Table>;
1125}
1126impl Table for Box<dyn Table> {
1127 fn get_cell(&self, r: usize, c: &str) -> Result<LiteralValue, ExcelError> {
1128 (**self).get_cell(r, c)
1129 }
1130 fn get_column(&self, c: &str) -> Result<Box<dyn Range>, ExcelError> {
1131 (**self).get_column(c)
1132 }
1133 fn columns(&self) -> Vec<String> {
1134 (**self).columns()
1135 }
1136 fn data_height(&self) -> usize {
1137 (**self).data_height()
1138 }
1139 fn has_headers(&self) -> bool {
1140 (**self).has_headers()
1141 }
1142 fn has_totals(&self) -> bool {
1143 (**self).has_totals()
1144 }
1145 fn headers_row(&self) -> Option<Box<dyn Range>> {
1146 (**self).headers_row()
1147 }
1148 fn totals_row(&self) -> Option<Box<dyn Range>> {
1149 (**self).totals_row()
1150 }
1151 fn data_body(&self) -> Option<Box<dyn Range>> {
1152 (**self).data_body()
1153 }
1154 fn clone_box(&self) -> Box<dyn Table> {
1155 (**self).clone_box()
1156 }
1157}
1158
1159pub trait ReferenceResolver: Send + Sync {
1162 fn resolve_cell_reference(
1163 &self,
1164 sheet: Option<&str>,
1165 row: u32,
1166 col: u32,
1167 ) -> Result<LiteralValue, ExcelError>;
1168}
1169pub trait RangeResolver: Send + Sync {
1170 fn resolve_range_reference(
1171 &self,
1172 sheet: Option<&str>,
1173 sr: Option<u32>,
1174 sc: Option<u32>,
1175 er: Option<u32>,
1176 ec: Option<u32>,
1177 ) -> Result<Box<dyn Range>, ExcelError>;
1178}
1179pub trait NamedRangeResolver: Send + Sync {
1180 fn resolve_named_range_reference(
1181 &self,
1182 name: &str,
1183 ) -> Result<Vec<Vec<LiteralValue>>, ExcelError>;
1184}
1185pub trait TableResolver: Send + Sync {
1186 fn resolve_table_reference(
1187 &self,
1188 tref: &formualizer_parse::parser::TableReference,
1189 ) -> Result<Box<dyn Table>, ExcelError>;
1190}
1191
1192pub trait SourceResolver: Send + Sync {
1193 fn source_scalar_version(&self, _name: &str) -> Option<u64> {
1194 None
1195 }
1196
1197 fn resolve_source_scalar(&self, name: &str) -> Result<LiteralValue, ExcelError> {
1198 Err(ExcelError::new(ExcelErrorKind::NImpl)
1199 .with_message(format!("Source scalar not supported: {name}")))
1200 }
1201
1202 fn source_table_version(&self, _name: &str) -> Option<u64> {
1203 None
1204 }
1205
1206 fn resolve_source_table(&self, name: &str) -> Result<Box<dyn Table>, ExcelError> {
1207 Err(ExcelError::new(ExcelErrorKind::NImpl)
1208 .with_message(format!("Source table not supported: {name}")))
1209 }
1210}
1211
1212pub trait Resolver: ReferenceResolver + RangeResolver + NamedRangeResolver + TableResolver {
1213 fn resolve_range_like(&self, r: &ReferenceType) -> Result<Box<dyn Range>, ExcelError> {
1214 match r {
1215 ReferenceType::Range {
1216 sheet,
1217 start_row,
1218 start_col,
1219 end_row,
1220 end_col,
1221 ..
1222 } => self.resolve_range_reference(
1223 sheet.as_deref(),
1224 *start_row,
1225 *start_col,
1226 *end_row,
1227 *end_col,
1228 ),
1229 ReferenceType::External(_) => Err(ExcelError::new(ExcelErrorKind::NImpl)
1230 .with_message("External references are not supported by Resolver".to_string())),
1231 ReferenceType::Table(tref) => {
1232 let t = self.resolve_table_reference(tref)?;
1233 match &tref.specifier {
1234 Some(TableSpecifier::Column(c)) => t.get_column(c),
1235 Some(TableSpecifier::ColumnRange(start, end)) => {
1236 let cols = t.columns();
1238 let start_key = start.to_lowercase();
1239 let end_key = end.to_lowercase();
1240 let start_idx = cols.iter().position(|n| n.to_lowercase() == start_key);
1241 let end_idx = cols.iter().position(|n| n.to_lowercase() == end_key);
1242 if let (Some(mut si), Some(mut ei)) = (start_idx, end_idx) {
1243 if si > ei {
1244 std::mem::swap(&mut si, &mut ei);
1245 }
1246 let h = t.data_height();
1248 let w = ei - si + 1;
1249 let mut rows = vec![vec![LiteralValue::Empty; w]; h];
1250 for (offset, ci) in (si..=ei).enumerate() {
1251 let cname = &cols[ci];
1252 let col_range = t.get_column(cname)?;
1253 let (rh, _) = col_range.dimensions();
1254 for (r, row) in rows.iter_mut().enumerate().take(h.min(rh)) {
1255 row[offset] = col_range.get(r, 0)?;
1256 }
1257 }
1258 Ok(Box::new(InMemoryRange::new(rows)))
1259 } else {
1260 Err(ExcelError::new(ExcelErrorKind::Ref).with_message(
1261 "Column range refers to unknown column(s)".to_string(),
1262 ))
1263 }
1264 }
1265 Some(TableSpecifier::SpecialItem(
1266 formualizer_parse::parser::SpecialItem::Headers,
1267 )) => {
1268 if let Some(h) = t.headers_row() {
1269 Ok(h)
1270 } else {
1271 Ok(Box::new(InMemoryRange::new(vec![])))
1272 }
1273 }
1274 Some(TableSpecifier::SpecialItem(
1275 formualizer_parse::parser::SpecialItem::Totals,
1276 )) => {
1277 if let Some(tr) = t.totals_row() {
1278 Ok(tr)
1279 } else {
1280 Ok(Box::new(InMemoryRange::new(vec![])))
1281 }
1282 }
1283 Some(TableSpecifier::SpecialItem(
1284 formualizer_parse::parser::SpecialItem::Data,
1285 )) => {
1286 if let Some(body) = t.data_body() {
1287 Ok(body)
1288 } else {
1289 Ok(Box::new(InMemoryRange::new(vec![])))
1290 }
1291 }
1292 Some(TableSpecifier::SpecialItem(
1293 formualizer_parse::parser::SpecialItem::All,
1294 )) => {
1295 let mut out: Vec<Vec<LiteralValue>> = Vec::new();
1297 if let Some(h) = t.headers_row() {
1298 out.extend(h.iter_rows());
1299 }
1300 if let Some(body) = t.data_body() {
1301 out.extend(body.iter_rows());
1302 }
1303 if let Some(tr) = t.totals_row() {
1304 out.extend(tr.iter_rows());
1305 }
1306 Ok(Box::new(InMemoryRange::new(out)))
1307 }
1308 Some(TableSpecifier::SpecialItem(
1309 formualizer_parse::parser::SpecialItem::ThisRow,
1310 )) => Err(ExcelError::new(ExcelErrorKind::NImpl).with_message(
1311 "@ (This Row) requires table-aware context; not yet supported".to_string(),
1312 )),
1313 Some(TableSpecifier::All) => {
1314 let mut out: Vec<Vec<LiteralValue>> = Vec::new();
1316 if let Some(h) = t.headers_row() {
1317 out.extend(h.iter_rows());
1318 }
1319 if let Some(body) = t.data_body() {
1320 out.extend(body.iter_rows());
1321 }
1322 if let Some(tr) = t.totals_row() {
1323 out.extend(tr.iter_rows());
1324 }
1325 Ok(Box::new(InMemoryRange::new(out)))
1326 }
1327 Some(TableSpecifier::Data) => {
1328 if let Some(body) = t.data_body() {
1329 Ok(body)
1330 } else {
1331 Ok(Box::new(InMemoryRange::new(vec![])))
1332 }
1333 }
1334 Some(TableSpecifier::Combination(_)) => Err(ExcelError::new(
1336 ExcelErrorKind::NImpl,
1337 )
1338 .with_message("Complex structured references not yet supported".to_string())),
1339 Some(TableSpecifier::Row(_)) => Err(ExcelError::new(ExcelErrorKind::NImpl)
1340 .with_message("Row selectors (@/index) not yet supported".to_string())),
1341 Some(TableSpecifier::Headers) | Some(TableSpecifier::Totals) => {
1342 Err(ExcelError::new(ExcelErrorKind::NImpl).with_message(
1343 "Legacy Headers/Totals variants not used; use SpecialItem".to_string(),
1344 ))
1345 }
1346 None => Err(ExcelError::new(ExcelErrorKind::Ref).with_message(
1347 "Table reference without specifier is unsupported".to_string(),
1348 )),
1349 }
1350 }
1351 ReferenceType::NamedRange(n) => {
1352 let v = self.resolve_named_range_reference(n)?;
1353 Ok(Box::new(InMemoryRange::new(v)))
1354 }
1355 ReferenceType::Cell {
1356 sheet, row, col, ..
1357 } => {
1358 let v = self.resolve_cell_reference(sheet.as_deref(), *row, *col)?;
1359 Ok(Box::new(InMemoryRange::new(vec![vec![v]])))
1360 }
1361 ReferenceType::Cell3D { .. } | ReferenceType::Range3D { .. } => {
1362 Err(ExcelError::new(ExcelErrorKind::NImpl)
1363 .with_message("3D references are not yet supported".to_string()))
1364 }
1365 }
1366 }
1367}
1368
1369pub trait FunctionProvider: Send + Sync {
1372 fn get_function(&self, ns: &str, name: &str) -> Option<Arc<dyn Function>>;
1373
1374 #[doc(hidden)]
1375 fn get_function_for_planning(&self, _ns: &str, _name: &str) -> Option<Arc<dyn Function>> {
1376 None
1377 }
1378
1379 #[doc(hidden)]
1382 fn planning_semantic_revision(&self) -> Option<u64> {
1383 None
1384 }
1385
1386 #[doc(hidden)]
1387 fn function_capabilities(&self, ns: &str, name: &str) -> Option<crate::function::FnCaps> {
1388 self.get_function(ns, name).map(|function| function.caps())
1389 }
1390
1391 fn function_semantic_identity(
1392 &self,
1393 ns: &str,
1394 name: &str,
1395 arity: usize,
1396 ) -> Option<crate::function_contract::FunctionSemanticIdentity> {
1397 crate::function_registry::resolve_semantic_identity(self, ns, name, arity)
1398 }
1399}
1400
1401pub trait EvaluationContext: Resolver + FunctionProvider + SourceResolver {
1402 fn thread_pool(&self) -> Option<&Arc<rayon::ThreadPool>> {
1405 None
1406 }
1407
1408 fn cancellation_token(&self) -> Option<crate::engine::CancelToken> {
1415 None
1416 }
1417
1418 fn chunk_hint(&self) -> Option<usize> {
1420 None
1421 }
1422
1423 fn resolve_range_view<'c>(
1426 &'c self,
1427 _reference: &ReferenceType,
1428 _current_sheet: &str,
1429 ) -> Result<RangeView<'c>, ExcelError> {
1430 Err(ExcelError::new(ExcelErrorKind::NImpl))
1431 }
1432
1433 fn resolve_cell_reference_value(
1438 &self,
1439 sheet: Option<&str>,
1440 row: u32,
1441 col: u32,
1442 current_sheet: &str,
1443 ) -> Result<LiteralValue, ExcelError> {
1444 let reference = ReferenceType::Cell {
1445 sheet: sheet.map(str::to_string),
1446 row,
1447 col,
1448 row_abs: true,
1449 col_abs: true,
1450 };
1451 let view = self.resolve_range_view(&reference, current_sheet)?;
1452 Ok(view.as_1x1().unwrap_or(LiteralValue::Empty))
1453 }
1454
1455 fn locale(&self) -> crate::locale::Locale {
1457 crate::locale::Locale::invariant()
1458 }
1459
1460 fn workbook_sheet_count(&self) -> Option<usize> {
1462 None
1463 }
1464
1465 fn sheet_index_by_name(&self, _sheet: &str) -> Option<usize> {
1467 None
1468 }
1469
1470 fn current_sheet_index(&self, current_sheet: &str) -> Option<usize> {
1472 self.sheet_index_by_name(current_sheet)
1473 }
1474
1475 fn inspect_reference(
1477 &self,
1478 _reference: &ReferenceType,
1479 _current_sheet: &str,
1480 ) -> Result<Option<ReferenceInfo>, ExcelError> {
1481 Ok(None)
1482 }
1483
1484 fn formula_text_at_cell(&self, _cell: CellRef) -> Result<Option<String>, ExcelError> {
1486 Ok(None)
1487 }
1488
1489 fn clock(&self) -> &dyn crate::timezone::ClockProvider {
1498 #[cfg(feature = "system-clock")]
1499 {
1500 static DEFAULT_CLOCK: std::sync::OnceLock<crate::timezone::SystemClock> =
1501 std::sync::OnceLock::new();
1502 DEFAULT_CLOCK.get_or_init(|| {
1503 crate::timezone::SystemClock::new(crate::timezone::TimeZoneSpec::default())
1504 })
1505 }
1506 #[cfg(not(feature = "system-clock"))]
1507 {
1508 static DEFAULT_CLOCK: std::sync::OnceLock<crate::timezone::FixedClock> =
1509 std::sync::OnceLock::new();
1510 DEFAULT_CLOCK.get_or_init(|| {
1511 crate::timezone::FixedClock::new(
1512 chrono::DateTime::UNIX_EPOCH,
1513 crate::timezone::TimeZoneSpec::Utc,
1514 )
1515 })
1516 }
1517 }
1518
1519 fn timezone(&self) -> &crate::timezone::TimeZoneSpec {
1523 self.clock().timezone()
1524 }
1525
1526 fn volatile_level(&self) -> VolatileLevel {
1528 VolatileLevel::Always
1529 }
1530
1531 fn workbook_seed(&self) -> u64 {
1533 0xF0F0_D0D0_AAAA_5555
1534 }
1535
1536 fn recalc_epoch(&self) -> u64 {
1538 0
1539 }
1540
1541 fn used_rows_for_columns(
1546 &self,
1547 _sheet: &str,
1548 _start_col: u32,
1549 _end_col: u32,
1550 ) -> Option<(u32, u32)> {
1551 None
1552 }
1553
1554 fn used_cols_for_rows(
1557 &self,
1558 _sheet: &str,
1559 _start_row: u32,
1560 _end_row: u32,
1561 ) -> Option<(u32, u32)> {
1562 None
1563 }
1564
1565 fn sheet_bounds(&self, _sheet: &str) -> Option<(u32, u32)> {
1567 None
1568 }
1569
1570 fn data_snapshot_id(&self) -> u64 {
1572 0
1573 }
1574
1575 fn backend_caps(&self) -> BackendCaps {
1577 BackendCaps::default()
1578 }
1579
1580 fn date_system(&self) -> crate::engine::DateSystem {
1585 crate::engine::DateSystem::Excel1900
1586 }
1587
1588 fn build_lookup_index(
1591 &self,
1592 _view: &RangeView<'_>,
1593 _axis: LookupAxis,
1594 ) -> Option<std::sync::Arc<LookupIndex>> {
1595 None
1596 }
1597
1598 fn build_criteria_mask(
1601 &self,
1602 _view: &RangeView<'_>,
1603 _col_in_view: usize,
1604 _pred: &crate::args::CriteriaPredicate,
1605 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1606 None
1607 }
1608
1609 fn build_row_visibility_mask(
1612 &self,
1613 _view: &RangeView<'_>,
1614 _mode: VisibilityMaskMode,
1615 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1616 None
1617 }
1618}
1619
1620#[derive(Copy, Clone, Debug, Default)]
1622pub struct BackendCaps {
1623 pub streaming: bool,
1625 pub used_region: bool,
1627 pub write: bool,
1629 pub tables: bool,
1631 pub async_stream: bool,
1633}
1634
1635#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1638pub enum VolatileLevel {
1639 Always,
1641 OnRecalc,
1643 OnOpen,
1645}
1646
1647pub trait FunctionContext<'ctx> {
1649 fn locale(&self) -> crate::locale::Locale;
1650 fn timezone(&self) -> &crate::timezone::TimeZoneSpec;
1651 fn clock(&self) -> &dyn crate::timezone::ClockProvider;
1652 fn thread_pool(&self) -> Option<&std::sync::Arc<rayon::ThreadPool>>;
1653 fn cancellation_token(&self) -> Option<crate::engine::CancelToken>;
1659 fn chunk_hint(&self) -> Option<usize>;
1660
1661 fn current_sheet(&self) -> &str;
1663
1664 fn workbook_sheet_count(&self) -> Option<usize> {
1665 None
1666 }
1667
1668 fn sheet_index_by_name(&self, _sheet: &str) -> Option<usize> {
1669 None
1670 }
1671
1672 fn current_sheet_index(&self) -> Option<usize> {
1673 self.sheet_index_by_name(self.current_sheet())
1674 }
1675
1676 fn inspect_reference(
1677 &self,
1678 _reference: &ReferenceType,
1679 ) -> Result<Option<ReferenceInfo>, ExcelError> {
1680 Ok(None)
1681 }
1682
1683 fn formula_text_at_cell(&self, _cell: CellRef) -> Result<Option<String>, ExcelError> {
1684 Ok(None)
1685 }
1686
1687 fn volatile_level(&self) -> VolatileLevel;
1688 fn workbook_seed(&self) -> u64;
1689 fn recalc_epoch(&self) -> u64;
1690 fn current_cell(&self) -> Option<CellRef>;
1691
1692 fn resolve_range_view(
1694 &self,
1695 _reference: &ReferenceType,
1696 _current_sheet: &str,
1697 ) -> Result<RangeView<'ctx>, ExcelError>;
1698
1699 fn rng_for_current(&self, fn_salt: u64) -> rand::rngs::SmallRng {
1703 use crate::rng::{compose_seed, small_rng_from_lanes};
1704 let (sheet_id, row, col) = self
1705 .current_cell()
1706 .map(|c| (c.sheet_id as u32, c.coord.row(), c.coord.col()))
1707 .unwrap_or((0, 0, 0));
1708 let epoch = match self.volatile_level() {
1710 VolatileLevel::OnRecalc => self.recalc_epoch(),
1711 _ => 0,
1712 };
1713 let (l0, l1) = compose_seed(self.workbook_seed(), sheet_id, row, col, fn_salt, epoch);
1714 small_rng_from_lanes(l0, l1)
1715 }
1716
1717 fn date_system(&self) -> crate::engine::DateSystem {
1719 crate::engine::DateSystem::Excel1900
1720 }
1721
1722 fn get_lookup_index(
1725 &self,
1726 _view: &RangeView<'_>,
1727 _axis: LookupAxis,
1728 ) -> Option<std::sync::Arc<LookupIndex>> {
1729 None
1730 }
1731
1732 fn get_criteria_mask(
1735 &self,
1736 _view: &RangeView<'_>,
1737 _col_in_view: usize,
1738 _pred: &crate::args::CriteriaPredicate,
1739 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1740 None
1741 }
1742
1743 fn get_row_visibility_mask(
1745 &self,
1746 _view: &RangeView<'_>,
1747 _mode: VisibilityMaskMode,
1748 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1749 None
1750 }
1751}
1752
1753pub struct DefaultFunctionContext<'a> {
1755 pub base: &'a dyn EvaluationContext,
1756 pub current: Option<CellRef>,
1757 pub current_sheet: &'a str,
1758}
1759
1760impl<'a> DefaultFunctionContext<'a> {
1761 pub fn new(
1762 base: &'a dyn EvaluationContext,
1763 current: Option<CellRef>,
1764 current_sheet: &'a str,
1765 ) -> Self {
1766 Self {
1767 base,
1768 current,
1769 current_sheet,
1770 }
1771 }
1772
1773 pub fn new_with_sheet(
1774 base: &'a dyn EvaluationContext,
1775 current: Option<CellRef>,
1776 current_sheet: &'a str,
1777 ) -> Self {
1778 Self::new(base, current, current_sheet)
1779 }
1780}
1781
1782impl<'a> FunctionContext<'a> for DefaultFunctionContext<'a> {
1783 fn locale(&self) -> crate::locale::Locale {
1784 self.base.locale()
1785 }
1786
1787 fn current_sheet(&self) -> &str {
1788 self.current_sheet
1789 }
1790
1791 fn workbook_sheet_count(&self) -> Option<usize> {
1792 self.base.workbook_sheet_count()
1793 }
1794
1795 fn sheet_index_by_name(&self, sheet: &str) -> Option<usize> {
1796 self.base.sheet_index_by_name(sheet)
1797 }
1798
1799 fn current_sheet_index(&self) -> Option<usize> {
1800 self.base.current_sheet_index(self.current_sheet)
1801 }
1802
1803 fn inspect_reference(
1804 &self,
1805 reference: &ReferenceType,
1806 ) -> Result<Option<ReferenceInfo>, ExcelError> {
1807 self.base.inspect_reference(reference, self.current_sheet)
1808 }
1809
1810 fn formula_text_at_cell(&self, cell: CellRef) -> Result<Option<String>, ExcelError> {
1811 self.base.formula_text_at_cell(cell)
1812 }
1813
1814 fn timezone(&self) -> &crate::timezone::TimeZoneSpec {
1815 self.base.timezone()
1816 }
1817
1818 fn clock(&self) -> &dyn crate::timezone::ClockProvider {
1819 self.base.clock()
1820 }
1821 fn thread_pool(&self) -> Option<&std::sync::Arc<rayon::ThreadPool>> {
1822 self.base.thread_pool()
1823 }
1824 fn cancellation_token(&self) -> Option<crate::engine::CancelToken> {
1825 self.base.cancellation_token()
1826 }
1827 fn chunk_hint(&self) -> Option<usize> {
1828 self.base.chunk_hint()
1829 }
1830
1831 fn volatile_level(&self) -> VolatileLevel {
1832 self.base.volatile_level()
1833 }
1834 fn workbook_seed(&self) -> u64 {
1835 self.base.workbook_seed()
1836 }
1837 fn recalc_epoch(&self) -> u64 {
1838 self.base.recalc_epoch()
1839 }
1840 fn current_cell(&self) -> Option<CellRef> {
1841 self.current
1842 }
1843
1844 fn resolve_range_view(
1845 &self,
1846 reference: &ReferenceType,
1847 current_sheet: &str,
1848 ) -> Result<RangeView<'a>, ExcelError> {
1849 self.base.resolve_range_view(reference, current_sheet)
1850 }
1851
1852 fn date_system(&self) -> crate::engine::DateSystem {
1855 self.base.date_system()
1856 }
1857
1858 fn get_lookup_index(
1859 &self,
1860 view: &RangeView<'_>,
1861 axis: LookupAxis,
1862 ) -> Option<std::sync::Arc<LookupIndex>> {
1863 self.base.build_lookup_index(view, axis)
1864 }
1865
1866 fn get_criteria_mask(
1867 &self,
1868 view: &RangeView<'_>,
1869 col_in_view: usize,
1870 pred: &crate::args::CriteriaPredicate,
1871 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1872 self.base.build_criteria_mask(view, col_in_view, pred)
1873 }
1874
1875 fn get_row_visibility_mask(
1876 &self,
1877 view: &RangeView<'_>,
1878 mode: VisibilityMaskMode,
1879 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1880 self.base.build_row_visibility_mask(view, mode)
1881 }
1882}