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(crate) fn date_system(&self) -> crate::engine::DateSystem {
314 self.interp.context.date_system()
315 }
316
317 pub fn is_omitted(&self) -> bool {
321 match &self.expr {
322 ArgumentExpr::Ast(node) => matches!(node.node_type, ASTNodeType::Omitted),
323 ArgumentExpr::Arena { id, data_store, .. } => matches!(
324 data_store.get_node(*id),
325 Some(crate::engine::arena::AstNodeData::Omitted)
326 ),
327 }
328 }
329
330 pub(crate) fn has_reference_semantics(&self) -> bool {
336 self.reference_attempt().is_some()
337 }
338
339 pub fn value(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
340 self.cached_value
341 .get_or_init(|| self.compute_value())
342 .clone()
343 }
344
345 pub(crate) fn value_for_text(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
351 if self.is_omitted() {
352 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(
353 String::new(),
354 )))
355 } else {
356 self.value()
357 }
358 }
359
360 pub(crate) fn resolve_once_for_text(&self) -> Result<ResolvedArgument<'b>, ExcelError> {
361 if self.is_omitted() {
362 Ok(ResolvedArgument::Value(crate::traits::CalcValue::Scalar(
363 LiteralValue::Text(String::new()),
364 )))
365 } else {
366 self.resolve_once()
367 }
368 }
369
370 fn compute_value(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
371 match &self.expr {
372 ArgumentExpr::Ast(node) => match &node.node_type {
373 ASTNodeType::Literal(v) => Ok(crate::traits::CalcValue::Scalar(v.clone())),
374 ASTNodeType::Omitted => {
377 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
378 }
379 _ => self.interp.evaluate_ast(node),
380 },
381 ArgumentExpr::Arena {
382 id,
383 data_store,
384 sheet_registry,
385 } => {
386 if matches!(
387 data_store.get_node(*id),
388 Some(crate::engine::arena::AstNodeData::Omitted)
389 ) {
390 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
391 } else {
392 self.interp
393 .evaluate_arena_ast(*id, data_store, sheet_registry)
394 }
395 }
396 }
397 }
398
399 pub fn value_with_env(
400 &self,
401 env: crate::interpreter::LocalEnv,
402 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
403 let scoped = self.interp.with_local_env(env);
404 match &self.expr {
405 ArgumentExpr::Ast(node) => match &node.node_type {
406 ASTNodeType::Literal(v) => Ok(crate::traits::CalcValue::Scalar(v.clone())),
407 ASTNodeType::Omitted => {
408 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
409 }
410 _ => scoped.evaluate_ast(node),
411 },
412 ArgumentExpr::Arena {
413 id,
414 data_store,
415 sheet_registry,
416 } => {
417 if matches!(
418 data_store.get_node(*id),
419 Some(crate::engine::arena::AstNodeData::Omitted)
420 ) {
421 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
422 } else {
423 scoped.evaluate_arena_ast(*id, data_store, sheet_registry)
424 }
425 }
426 }
427 }
428
429 pub fn current_env(&self) -> crate::interpreter::LocalEnv {
430 self.interp.local_env().clone()
431 }
432
433 pub fn inline_array_literal(&self) -> Result<Option<Vec<Vec<LiteralValue>>>, ExcelError> {
434 match &self.expr {
435 ArgumentExpr::Ast(node) => match &node.node_type {
436 ASTNodeType::Literal(LiteralValue::Array(arr)) => Ok(Some(arr.clone())),
437 _ => Ok(None),
438 },
439 ArgumentExpr::Arena {
440 id,
441 data_store,
442 sheet_registry,
443 } => {
444 let node = data_store.get_node(*id).ok_or_else(|| {
445 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
446 })?;
447 match node {
448 crate::engine::arena::AstNodeData::Literal(vref) => {
449 match data_store.retrieve_value(*vref) {
450 LiteralValue::Array(arr) => Ok(Some(arr)),
451 _ => Ok(None),
452 }
453 }
454 _ => {
455 let _ = sheet_registry;
458 Ok(None)
459 }
460 }
461 }
462 }
463 }
464
465 fn reference_for_eval(&self) -> Result<ReferenceType, ExcelError> {
466 match &self.expr {
467 ArgumentExpr::Ast(node) => match &node.node_type {
468 ASTNodeType::Reference { reference, .. } => {
469 self.interp.reference_for_current_offset(reference)
470 }
471 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
472 self.interp.evaluate_ast_as_reference(node)
473 }
474 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
475 .with_message("Expected a reference (by-ref argument)")),
476 },
477 ArgumentExpr::Arena {
478 id,
479 data_store,
480 sheet_registry,
481 } => {
482 let node = data_store.get_node(*id).ok_or_else(|| {
483 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
484 })?;
485 match node {
486 crate::engine::arena::AstNodeData::Reference { ref_type, .. } => {
487 let reference = data_store
488 .reconstruct_reference_type_for_eval(ref_type, sheet_registry);
489 self.interp.reference_for_current_offset(&reference)
490 }
491 crate::engine::arena::AstNodeData::Function { .. }
492 | crate::engine::arena::AstNodeData::BinaryOp { .. } => self
493 .interp
494 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry),
495 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
496 .with_message("Expected a reference (by-ref argument)")),
497 }
498 }
499 }
500 }
501
502 fn reference_attempt(&self) -> Option<Result<ReferenceType, ExcelError>> {
503 match &self.expr {
504 ArgumentExpr::Ast(node) => match &node.node_type {
505 ASTNodeType::Reference { reference, .. } => {
506 Some(self.interp.reference_for_current_offset(reference))
507 }
508 ASTNodeType::BinaryOp { op, .. } if op == ":" => {
509 Some(self.interp.evaluate_ast_as_reference(node))
510 }
511 ASTNodeType::Function { name, .. }
512 if self
513 .interp
514 .context
515 .function_capabilities("", name)
516 .is_some_and(|caps| {
517 caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)
518 }) =>
519 {
520 self.interp.try_evaluate_ast_as_reference(node)
521 }
522 _ => None,
523 },
524 ArgumentExpr::Arena {
525 id,
526 data_store,
527 sheet_registry,
528 } => {
529 let node = match data_store.get_node(*id) {
530 Some(node) => node,
531 None => {
532 return Some(Err(
533 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
534 ));
535 }
536 };
537 match node {
538 crate::engine::arena::AstNodeData::Reference { ref_type, .. } => {
539 let reference = data_store
540 .reconstruct_reference_type_for_eval(ref_type, sheet_registry);
541 Some(self.interp.reference_for_current_offset(&reference))
542 }
543 crate::engine::arena::AstNodeData::BinaryOp { op_id, .. }
544 if data_store.resolve_ast_string(*op_id) == ":" =>
545 {
546 Some(self.interp.evaluate_arena_ast_as_reference(
547 *id,
548 data_store,
549 sheet_registry,
550 ))
551 }
552 crate::engine::arena::AstNodeData::Function { name_id, .. } => {
553 let name = data_store.resolve_ast_string(*name_id);
554 if self
555 .interp
556 .context
557 .function_capabilities("", name)
558 .is_some_and(|caps| {
559 caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)
560 })
561 {
562 self.interp.try_evaluate_arena_ast_as_reference(
563 *id,
564 data_store,
565 sheet_registry,
566 )
567 } else {
568 None
569 }
570 }
571 _ => None,
572 }
573 }
574 }
575 }
576
577 pub(crate) fn resolve_once(&self) -> Result<ResolvedArgument<'b>, ExcelError> {
583 self.cached_resolved
584 .get_or_init(|| self.compute_resolved_argument())
585 .clone()
586 }
587
588 fn with_context_cancel_token(&self, view: RangeView<'b>) -> RangeView<'b> {
589 match self.interp.context.cancellation_token() {
590 Some(token) => view.with_cancel_token(Some(token)),
591 None => view,
592 }
593 }
594
595 fn compute_resolved_argument(&self) -> Result<ResolvedArgument<'b>, ExcelError> {
596 if let Some(attempt) = self.reference_attempt() {
597 let reference = match attempt {
598 Ok(reference) => reference,
599 Err(error) if error.kind == ExcelErrorKind::Cancelled => return Err(error),
600 Err(error) => return Ok(ResolvedArgument::ReferenceError(error)),
601 };
602 return match self
603 .interp
604 .context
605 .resolve_range_view(&reference, self.interp.current_sheet())
606 {
607 Ok(view) => Ok(ResolvedArgument::Range(
608 self.with_context_cancel_token(view),
609 )),
610 Err(error) if error.kind == ExcelErrorKind::Cancelled => Err(error),
611 Err(error) => Ok(ResolvedArgument::ReferenceError(error)),
612 };
613 }
614
615 match self.value()? {
616 CalcValue::Range(view) => Ok(ResolvedArgument::Range(
617 self.with_context_cancel_token(view),
618 )),
619 CalcValue::Scalar(LiteralValue::Array(rows)) => {
620 let view = RangeView::try_from_owned_rows(
621 rows,
622 self.interp.context.date_system(),
623 self.interp.context.cancellation_token(),
624 )?;
625 Ok(ResolvedArgument::Range(view))
626 }
627 other => Ok(ResolvedArgument::Value(other)),
628 }
629 }
630
631 pub fn range(&self) -> Result<Box<dyn Range>, ExcelError> {
632 match &self.expr {
633 ArgumentExpr::Ast(node) => match &node.node_type {
634 ASTNodeType::Reference { reference, .. } => {
635 let reference = self.interp.reference_for_current_offset(reference)?;
637 let view = self
638 .interp
639 .context
640 .resolve_range_view(&reference, self.interp.current_sheet())?;
641 let (rows, cols) = view.dims();
642 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
643 view.for_each_row(&mut |row| {
644 let row_data: Vec<LiteralValue> = (0..cols)
645 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
646 .collect();
647 out.push(row_data);
648 Ok(())
649 })?;
650 Ok(Box::new(InMemoryRange::new(out)))
651 }
652 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
653 let reference = self.reference_for_eval()?;
654 let view = self
655 .interp
656 .context
657 .resolve_range_view(&reference, self.interp.current_sheet())?;
658 let (rows, cols) = view.dims();
659 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
660 view.for_each_row(&mut |row| {
661 let row_data: Vec<LiteralValue> = (0..cols)
662 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
663 .collect();
664 out.push(row_data);
665 Ok(())
666 })?;
667 Ok(Box::new(InMemoryRange::new(out)))
668 }
669 ASTNodeType::Array(rows) => {
670 let mut materialized = Vec::new();
671 for row in rows {
672 let mut materialized_row = Vec::new();
673 for cell in row {
674 materialized_row.push(self.interp.evaluate_ast(cell)?.into_literal());
675 }
676 materialized.push(materialized_row);
677 }
678 Ok(Box::new(InMemoryRange::new(materialized)))
679 }
680 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
681 .with_message(format!("Expected a range, got {:?}", node.node_type))),
682 },
683 ArgumentExpr::Arena { id, data_store, .. } => {
684 let node = data_store.get_node(*id).ok_or_else(|| {
685 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
686 })?;
687
688 match node {
689 crate::engine::arena::AstNodeData::Reference { .. }
690 | crate::engine::arena::AstNodeData::Function { .. }
691 | crate::engine::arena::AstNodeData::BinaryOp { .. } => {
692 let reference = self.reference_for_eval()?;
693 let view = self
694 .interp
695 .context
696 .resolve_range_view(&reference, self.interp.current_sheet())?;
697 let (rows, cols) = view.dims();
698 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
699 view.for_each_row(&mut |row| {
700 let row_data: Vec<LiteralValue> = (0..cols)
701 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
702 .collect();
703 out.push(row_data);
704 Ok(())
705 })?;
706 Ok(Box::new(InMemoryRange::new(out)))
707 }
708 crate::engine::arena::AstNodeData::Array { .. } => {
709 let (rows, cols, elements) =
710 data_store.get_array_elems(*id).ok_or_else(|| {
711 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
712 })?;
713 let rows_usize = rows as usize;
714 let cols_usize = cols as usize;
715 let mut materialized: Vec<Vec<LiteralValue>> =
716 Vec::with_capacity(rows_usize);
717 for r in 0..rows_usize {
718 let mut row = Vec::with_capacity(cols_usize);
719 for c in 0..cols_usize {
720 let idx = r * cols_usize + c;
721 let elem_id = elements.get(idx).copied().ok_or_else(|| {
722 ExcelError::new(ExcelErrorKind::Value)
723 .with_message("Invalid array")
724 })?;
725 let v = self.interp.evaluate_arena_ast(
726 elem_id,
727 data_store,
728 self.sheet_registry(),
729 )?;
730 row.push(v.into_literal());
731 }
732 materialized.push(row);
733 }
734 Ok(Box::new(InMemoryRange::new(materialized)))
735 }
736 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
737 .with_message("Argument cannot be interpreted as a range.")),
738 }
739 }
740 }
741 }
742
743 fn sheet_registry(&self) -> &crate::engine::sheet_registry::SheetRegistry {
744 match &self.expr {
745 ArgumentExpr::Ast(_) => {
746 unreachable!("sheet_registry only used for arena ArgumentHandle")
748 }
749 ArgumentExpr::Arena { sheet_registry, .. } => sheet_registry,
750 }
751 }
752
753 pub fn range_view(&self) -> Result<RangeView<'b>, ExcelError> {
761 match self.resolve_once()? {
762 ResolvedArgument::Range(view) => Ok(view),
763 ResolvedArgument::ReferenceError(error) => Err(error),
766 ResolvedArgument::Value(CalcValue::Range(view)) => {
771 Ok(self.with_context_cancel_token(view))
772 }
773 ResolvedArgument::Value(CalcValue::Scalar(LiteralValue::Array(rows))) => {
774 RangeView::try_from_owned_rows(
775 rows,
776 self.interp.context.date_system(),
777 self.interp.context.cancellation_token(),
778 )
779 }
780 ResolvedArgument::Value(_) => Err(ExcelError::new(ExcelErrorKind::Ref)
781 .with_message("Argument cannot be interpreted as a range.")),
782 }
783 }
784
785 pub fn range_view_or_scalar(&self) -> Result<RangeView<'b>, ExcelError> {
805 match self.resolve_once()? {
806 ResolvedArgument::Range(view) => Ok(view),
807 ResolvedArgument::ReferenceError(error) => Err(error),
808 ResolvedArgument::Value(CalcValue::Range(view)) => {
809 Ok(self.with_context_cancel_token(view))
810 }
811 ResolvedArgument::Value(CalcValue::Scalar(LiteralValue::Array(rows))) => {
812 RangeView::try_from_owned_rows(
813 rows,
814 self.interp.context.date_system(),
815 self.interp.context.cancellation_token(),
816 )
817 }
818 ResolvedArgument::Value(CalcValue::Scalar(LiteralValue::Error(error))) => Err(error),
821 ResolvedArgument::Value(CalcValue::Scalar(scalar)) => RangeView::try_from_owned_rows(
822 vec![vec![scalar]],
823 self.interp.context.date_system(),
824 self.interp.context.cancellation_token(),
825 ),
826 ResolvedArgument::Value(CalcValue::Callable(_)) => {
828 Err(ExcelError::new(ExcelErrorKind::Ref)
829 .with_message("Argument cannot be interpreted as a range."))
830 }
831 }
832 }
833
834 pub fn value_or_range(&self) -> Result<EvaluatedArg<'_>, ExcelError> {
835 self.range().map(EvaluatedArg::Range).or_else(|_| {
836 self.value()
837 .map(|cv| EvaluatedArg::LiteralValue(Cow::Owned(cv.into_literal())))
838 })
839 }
840
841 pub fn lazy_values_owned(
846 &'a self,
847 ) -> Result<Box<dyn Iterator<Item = LiteralValue> + 'a>, ExcelError> {
848 match &self.expr {
849 ArgumentExpr::Ast(node) => match &node.node_type {
850 ASTNodeType::Reference { .. } => {
851 let view = self.range_view()?;
852 let mut values: Vec<LiteralValue> = Vec::new();
853 view.for_each_cell(&mut |v| {
854 values.push(v.clone());
855 Ok(())
856 })?;
857 Ok(Box::new(values.into_iter()))
858 }
859 ASTNodeType::Array(rows) => {
860 struct ArrayEvalIter<'a, 'b> {
861 rows: &'a [Vec<ASTNode>],
862 r: usize,
863 c: usize,
864 interp: &'a Interpreter<'b>,
865 }
866 impl<'a, 'b> Iterator for ArrayEvalIter<'a, 'b> {
867 type Item = LiteralValue;
868 fn next(&mut self) -> Option<Self::Item> {
869 if self.rows.is_empty() {
870 return None;
871 }
872 let rows = self.rows;
873 let mut r = self.r;
874 let mut c = self.c;
875 if r >= rows.len() {
876 return None;
877 }
878 let node = &rows[r][c];
879 c += 1;
881 if c >= rows[r].len() {
882 r += 1;
883 c = 0;
884 }
885 self.r = r;
886 self.c = c;
887 match self.interp.evaluate_ast(node) {
888 Ok(cv) => Some(cv.into_literal()),
889 Err(e) => Some(LiteralValue::Error(e)),
890 }
891 }
892 }
893 let it = ArrayEvalIter {
894 rows,
895 r: 0,
896 c: 0,
897 interp: self.interp,
898 };
899 Ok(Box::new(it))
900 }
901 _ => {
902 let v = self.value()?.into_literal();
904 Ok(Box::new(std::iter::once(v)))
905 }
906 },
907 ArgumentExpr::Arena {
908 id,
909 data_store,
910 sheet_registry,
911 } => {
912 let node = data_store.get_node(*id).ok_or_else(|| {
913 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
914 })?;
915
916 match node {
917 crate::engine::arena::AstNodeData::Reference { .. } => {
918 let view = self.range_view()?;
919 let mut values: Vec<LiteralValue> = Vec::new();
920 view.for_each_cell(&mut |v| {
921 values.push(v.clone());
922 Ok(())
923 })?;
924 Ok(Box::new(values.into_iter()))
925 }
926 crate::engine::arena::AstNodeData::Array { .. } => {
927 let (rows, cols, elements) =
928 data_store.get_array_elems(*id).ok_or_else(|| {
929 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
930 })?;
931
932 struct ArenaArrayEvalIter<'a, 'b> {
933 elements: &'a [crate::engine::arena::AstNodeId],
934 idx: usize,
935 interp: &'a Interpreter<'b>,
936 data_store: &'a crate::engine::arena::DataStore,
937 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
938 }
939
940 impl<'a, 'b> Iterator for ArenaArrayEvalIter<'a, 'b> {
941 type Item = LiteralValue;
942
943 fn next(&mut self) -> Option<Self::Item> {
944 let id = self.elements.get(self.idx).copied()?;
945 self.idx += 1;
946 match self.interp.evaluate_arena_ast(
947 id,
948 self.data_store,
949 self.sheet_registry,
950 ) {
951 Ok(cv) => Some(cv.into_literal()),
952 Err(e) => Some(LiteralValue::Error(e)),
953 }
954 }
955 }
956
957 let _ = (rows, cols);
958 let it = ArenaArrayEvalIter {
959 elements,
960 idx: 0,
961 interp: self.interp,
962 data_store,
963 sheet_registry,
964 };
965 Ok(Box::new(it))
966 }
967 _ => {
968 let v = self
969 .interp
970 .evaluate_arena_ast(*id, data_store, sheet_registry)?;
971 Ok(Box::new(std::iter::once(v.into_literal())))
972 }
973 }
974 }
975 }
976 }
977
978 pub fn ast(&self) -> &ASTNode {
979 match &self.expr {
980 ArgumentExpr::Ast(node) => node,
981 ArgumentExpr::Arena {
982 id,
983 data_store,
984 sheet_registry,
985 } => self.cached_ast.get_or_init(|| {
986 data_store
987 .retrieve_ast(*id, sheet_registry)
988 .unwrap_or_else(|| ASTNode {
989 node_type: ASTNodeType::Literal(LiteralValue::Error(
990 ExcelError::new(ExcelErrorKind::Value)
991 .with_message("Missing formula AST"),
992 )),
993 source_token: None,
994 contains_volatile: false,
995 })
996 }),
997 }
998 }
999
1000 pub fn as_reference(&self) -> Result<&ReferenceType, ExcelError> {
1003 match &self.expr {
1004 ArgumentExpr::Ast(node) => match &node.node_type {
1005 ASTNodeType::Reference { reference, .. } => Ok(reference),
1006 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1007 .with_message("Expected a reference (by-ref argument)")),
1008 },
1009 ArgumentExpr::Arena { .. } => {
1010 let reference = self.reference_for_eval()?;
1011 Ok(self.cached_ref.get_or_init(|| reference))
1012 }
1013 }
1014 }
1015
1016 pub fn as_reference_or_eval(&self) -> Result<ReferenceType, ExcelError> {
1019 match &self.expr {
1020 ArgumentExpr::Ast(node) => match &node.node_type {
1021 ASTNodeType::Reference { reference, .. } => {
1022 self.interp.reference_for_current_offset(reference)
1023 }
1024 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
1025 self.interp.evaluate_ast_as_reference(node)
1026 }
1027 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1028 .with_message("Argument is not a reference")),
1029 },
1030 ArgumentExpr::Arena {
1031 id,
1032 data_store,
1033 sheet_registry,
1034 } => {
1035 let node = data_store.get_node(*id).ok_or_else(|| {
1036 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
1037 })?;
1038
1039 match node {
1040 crate::engine::arena::AstNodeData::Reference { .. } => {
1041 self.reference_for_eval()
1042 }
1043 crate::engine::arena::AstNodeData::Function { .. }
1044 | crate::engine::arena::AstNodeData::BinaryOp { .. } => self
1045 .interp
1046 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry),
1047 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1048 .with_message("Argument is not a reference")),
1049 }
1050 }
1051 }
1052 }
1053
1054 pub fn matches_kind(&self, k: formualizer_common::ArgKind) -> Result<bool, ExcelError> {
1056 Ok(match k {
1057 formualizer_common::ArgKind::Any => true,
1058 formualizer_common::ArgKind::Range => self.range().is_ok(),
1059 formualizer_common::ArgKind::Number => matches!(
1060 self.value()?.into_literal(),
1061 LiteralValue::Number(_) | LiteralValue::Int(_)
1062 ),
1063 formualizer_common::ArgKind::Text => {
1064 matches!(self.value()?.into_literal(), LiteralValue::Text(_))
1065 }
1066 formualizer_common::ArgKind::Logical => {
1067 matches!(self.value()?.into_literal(), LiteralValue::Boolean(_))
1068 }
1069 })
1070 }
1071}
1072
1073#[derive(Debug, Clone)]
1075pub struct InMemoryRange {
1076 data: Vec<Vec<LiteralValue>>,
1077}
1078impl InMemoryRange {
1079 pub fn new(d: Vec<Vec<LiteralValue>>) -> Self {
1080 Self { data: d }
1081 }
1082}
1083impl Range for InMemoryRange {
1084 fn get(&self, r: usize, c: usize) -> Result<LiteralValue, ExcelError> {
1085 Ok(self
1086 .data
1087 .get(r)
1088 .and_then(|row| row.get(c))
1089 .cloned()
1090 .unwrap_or(LiteralValue::Empty))
1091 }
1092 fn dimensions(&self) -> (usize, usize) {
1093 (self.data.len(), self.data.first().map_or(0, |r| r.len()))
1094 }
1095 fn as_any(&self) -> &dyn Any {
1096 self
1097 }
1098}
1099
1100pub trait Table: Debug + Send + Sync {
1103 fn get_cell(&self, row: usize, column: &str) -> Result<LiteralValue, ExcelError>;
1104 fn get_column(&self, column: &str) -> Result<Box<dyn Range>, ExcelError>;
1105 fn columns(&self) -> Vec<String> {
1107 vec![]
1108 }
1109 fn data_height(&self) -> usize {
1111 0
1112 }
1113 fn has_headers(&self) -> bool {
1115 false
1116 }
1117 fn has_totals(&self) -> bool {
1119 false
1120 }
1121 fn headers_row(&self) -> Option<Box<dyn Range>> {
1123 None
1124 }
1125 fn totals_row(&self) -> Option<Box<dyn Range>> {
1127 None
1128 }
1129 fn data_body(&self) -> Option<Box<dyn Range>> {
1131 None
1132 }
1133 fn clone_box(&self) -> Box<dyn Table>;
1134}
1135impl Table for Box<dyn Table> {
1136 fn get_cell(&self, r: usize, c: &str) -> Result<LiteralValue, ExcelError> {
1137 (**self).get_cell(r, c)
1138 }
1139 fn get_column(&self, c: &str) -> Result<Box<dyn Range>, ExcelError> {
1140 (**self).get_column(c)
1141 }
1142 fn columns(&self) -> Vec<String> {
1143 (**self).columns()
1144 }
1145 fn data_height(&self) -> usize {
1146 (**self).data_height()
1147 }
1148 fn has_headers(&self) -> bool {
1149 (**self).has_headers()
1150 }
1151 fn has_totals(&self) -> bool {
1152 (**self).has_totals()
1153 }
1154 fn headers_row(&self) -> Option<Box<dyn Range>> {
1155 (**self).headers_row()
1156 }
1157 fn totals_row(&self) -> Option<Box<dyn Range>> {
1158 (**self).totals_row()
1159 }
1160 fn data_body(&self) -> Option<Box<dyn Range>> {
1161 (**self).data_body()
1162 }
1163 fn clone_box(&self) -> Box<dyn Table> {
1164 (**self).clone_box()
1165 }
1166}
1167
1168pub trait ReferenceResolver: Send + Sync {
1171 fn resolve_cell_reference(
1172 &self,
1173 sheet: Option<&str>,
1174 row: u32,
1175 col: u32,
1176 ) -> Result<LiteralValue, ExcelError>;
1177}
1178pub trait RangeResolver: Send + Sync {
1179 fn resolve_range_reference(
1180 &self,
1181 sheet: Option<&str>,
1182 sr: Option<u32>,
1183 sc: Option<u32>,
1184 er: Option<u32>,
1185 ec: Option<u32>,
1186 ) -> Result<Box<dyn Range>, ExcelError>;
1187}
1188pub trait NamedRangeResolver: Send + Sync {
1189 fn resolve_named_range_reference(
1190 &self,
1191 name: &str,
1192 ) -> Result<Vec<Vec<LiteralValue>>, ExcelError>;
1193}
1194pub trait TableResolver: Send + Sync {
1195 fn resolve_table_reference(
1196 &self,
1197 tref: &formualizer_parse::parser::TableReference,
1198 ) -> Result<Box<dyn Table>, ExcelError>;
1199}
1200
1201pub trait SourceResolver: Send + Sync {
1202 fn source_scalar_version(&self, _name: &str) -> Option<u64> {
1203 None
1204 }
1205
1206 fn resolve_source_scalar(&self, name: &str) -> Result<LiteralValue, ExcelError> {
1207 Err(ExcelError::new(ExcelErrorKind::NImpl)
1208 .with_message(format!("Source scalar not supported: {name}")))
1209 }
1210
1211 fn source_table_version(&self, _name: &str) -> Option<u64> {
1212 None
1213 }
1214
1215 fn resolve_source_table(&self, name: &str) -> Result<Box<dyn Table>, ExcelError> {
1216 Err(ExcelError::new(ExcelErrorKind::NImpl)
1217 .with_message(format!("Source table not supported: {name}")))
1218 }
1219}
1220
1221pub trait Resolver: ReferenceResolver + RangeResolver + NamedRangeResolver + TableResolver {
1222 fn resolve_range_like(&self, r: &ReferenceType) -> Result<Box<dyn Range>, ExcelError> {
1223 match r {
1224 ReferenceType::Range {
1225 sheet,
1226 start_row,
1227 start_col,
1228 end_row,
1229 end_col,
1230 ..
1231 } => self.resolve_range_reference(
1232 sheet.as_deref(),
1233 *start_row,
1234 *start_col,
1235 *end_row,
1236 *end_col,
1237 ),
1238 ReferenceType::External(_) => Err(ExcelError::new(ExcelErrorKind::NImpl)
1239 .with_message("External references are not supported by Resolver".to_string())),
1240 ReferenceType::Table(tref) => {
1241 let t = self.resolve_table_reference(tref)?;
1242 match &tref.specifier {
1243 Some(TableSpecifier::Column(c)) => t.get_column(c),
1244 Some(TableSpecifier::ColumnRange(start, end)) => {
1245 let cols = t.columns();
1247 let start_key = start.to_lowercase();
1248 let end_key = end.to_lowercase();
1249 let start_idx = cols.iter().position(|n| n.to_lowercase() == start_key);
1250 let end_idx = cols.iter().position(|n| n.to_lowercase() == end_key);
1251 if let (Some(mut si), Some(mut ei)) = (start_idx, end_idx) {
1252 if si > ei {
1253 std::mem::swap(&mut si, &mut ei);
1254 }
1255 let h = t.data_height();
1257 let w = ei - si + 1;
1258 let mut rows = vec![vec![LiteralValue::Empty; w]; h];
1259 for (offset, ci) in (si..=ei).enumerate() {
1260 let cname = &cols[ci];
1261 let col_range = t.get_column(cname)?;
1262 let (rh, _) = col_range.dimensions();
1263 for (r, row) in rows.iter_mut().enumerate().take(h.min(rh)) {
1264 row[offset] = col_range.get(r, 0)?;
1265 }
1266 }
1267 Ok(Box::new(InMemoryRange::new(rows)))
1268 } else {
1269 Err(ExcelError::new(ExcelErrorKind::Ref).with_message(
1270 "Column range refers to unknown column(s)".to_string(),
1271 ))
1272 }
1273 }
1274 Some(TableSpecifier::SpecialItem(
1275 formualizer_parse::parser::SpecialItem::Headers,
1276 )) => {
1277 if let Some(h) = t.headers_row() {
1278 Ok(h)
1279 } else {
1280 Ok(Box::new(InMemoryRange::new(vec![])))
1281 }
1282 }
1283 Some(TableSpecifier::SpecialItem(
1284 formualizer_parse::parser::SpecialItem::Totals,
1285 )) => {
1286 if let Some(tr) = t.totals_row() {
1287 Ok(tr)
1288 } else {
1289 Ok(Box::new(InMemoryRange::new(vec![])))
1290 }
1291 }
1292 Some(TableSpecifier::SpecialItem(
1293 formualizer_parse::parser::SpecialItem::Data,
1294 )) => {
1295 if let Some(body) = t.data_body() {
1296 Ok(body)
1297 } else {
1298 Ok(Box::new(InMemoryRange::new(vec![])))
1299 }
1300 }
1301 Some(TableSpecifier::SpecialItem(
1302 formualizer_parse::parser::SpecialItem::All,
1303 )) => {
1304 let mut out: Vec<Vec<LiteralValue>> = Vec::new();
1306 if let Some(h) = t.headers_row() {
1307 out.extend(h.iter_rows());
1308 }
1309 if let Some(body) = t.data_body() {
1310 out.extend(body.iter_rows());
1311 }
1312 if let Some(tr) = t.totals_row() {
1313 out.extend(tr.iter_rows());
1314 }
1315 Ok(Box::new(InMemoryRange::new(out)))
1316 }
1317 Some(TableSpecifier::SpecialItem(
1318 formualizer_parse::parser::SpecialItem::ThisRow,
1319 )) => Err(ExcelError::new(ExcelErrorKind::NImpl).with_message(
1320 "@ (This Row) requires table-aware context; not yet supported".to_string(),
1321 )),
1322 Some(TableSpecifier::All) => {
1323 let mut out: Vec<Vec<LiteralValue>> = Vec::new();
1325 if let Some(h) = t.headers_row() {
1326 out.extend(h.iter_rows());
1327 }
1328 if let Some(body) = t.data_body() {
1329 out.extend(body.iter_rows());
1330 }
1331 if let Some(tr) = t.totals_row() {
1332 out.extend(tr.iter_rows());
1333 }
1334 Ok(Box::new(InMemoryRange::new(out)))
1335 }
1336 Some(TableSpecifier::Data) => {
1337 if let Some(body) = t.data_body() {
1338 Ok(body)
1339 } else {
1340 Ok(Box::new(InMemoryRange::new(vec![])))
1341 }
1342 }
1343 Some(TableSpecifier::Combination(_)) => Err(ExcelError::new(
1345 ExcelErrorKind::NImpl,
1346 )
1347 .with_message("Complex structured references not yet supported".to_string())),
1348 Some(TableSpecifier::Row(_)) => Err(ExcelError::new(ExcelErrorKind::NImpl)
1349 .with_message("Row selectors (@/index) not yet supported".to_string())),
1350 Some(TableSpecifier::Headers) | Some(TableSpecifier::Totals) => {
1351 Err(ExcelError::new(ExcelErrorKind::NImpl).with_message(
1352 "Legacy Headers/Totals variants not used; use SpecialItem".to_string(),
1353 ))
1354 }
1355 None => Err(ExcelError::new(ExcelErrorKind::Ref).with_message(
1356 "Table reference without specifier is unsupported".to_string(),
1357 )),
1358 }
1359 }
1360 ReferenceType::NamedRange(n) => {
1361 let v = self.resolve_named_range_reference(n)?;
1362 Ok(Box::new(InMemoryRange::new(v)))
1363 }
1364 ReferenceType::Cell {
1365 sheet, row, col, ..
1366 } => {
1367 let v = self.resolve_cell_reference(sheet.as_deref(), *row, *col)?;
1368 Ok(Box::new(InMemoryRange::new(vec![vec![v]])))
1369 }
1370 ReferenceType::Cell3D { .. } | ReferenceType::Range3D { .. } => {
1371 Err(ExcelError::new(ExcelErrorKind::NImpl)
1372 .with_message("3D references are not yet supported".to_string()))
1373 }
1374 }
1375 }
1376}
1377
1378pub trait FunctionProvider: Send + Sync {
1381 fn get_function(&self, ns: &str, name: &str) -> Option<Arc<dyn Function>>;
1382
1383 #[doc(hidden)]
1384 fn get_function_for_planning(&self, _ns: &str, _name: &str) -> Option<Arc<dyn Function>> {
1385 None
1386 }
1387
1388 #[doc(hidden)]
1391 fn planning_semantic_revision(&self) -> Option<u64> {
1392 None
1393 }
1394
1395 #[doc(hidden)]
1396 fn function_capabilities(&self, ns: &str, name: &str) -> Option<crate::function::FnCaps> {
1397 self.get_function(ns, name).map(|function| function.caps())
1398 }
1399
1400 fn function_semantic_identity(
1401 &self,
1402 ns: &str,
1403 name: &str,
1404 arity: usize,
1405 ) -> Option<crate::function_contract::FunctionSemanticIdentity> {
1406 crate::function_registry::resolve_semantic_identity(self, ns, name, arity)
1407 }
1408}
1409
1410pub trait EvaluationContext: Resolver + FunctionProvider + SourceResolver {
1411 fn thread_pool(&self) -> Option<&Arc<rayon::ThreadPool>> {
1414 None
1415 }
1416
1417 fn cancellation_token(&self) -> Option<crate::engine::CancelToken> {
1424 None
1425 }
1426
1427 fn chunk_hint(&self) -> Option<usize> {
1429 None
1430 }
1431
1432 fn resolve_range_view<'c>(
1435 &'c self,
1436 _reference: &ReferenceType,
1437 _current_sheet: &str,
1438 ) -> Result<RangeView<'c>, ExcelError> {
1439 Err(ExcelError::new(ExcelErrorKind::NImpl))
1440 }
1441
1442 fn resolve_cell_reference_value(
1447 &self,
1448 sheet: Option<&str>,
1449 row: u32,
1450 col: u32,
1451 current_sheet: &str,
1452 ) -> Result<LiteralValue, ExcelError> {
1453 let reference = ReferenceType::Cell {
1454 sheet: sheet.map(str::to_string),
1455 row,
1456 col,
1457 row_abs: true,
1458 col_abs: true,
1459 };
1460 let view = self.resolve_range_view(&reference, current_sheet)?;
1461 Ok(view.as_1x1().unwrap_or(LiteralValue::Empty))
1462 }
1463
1464 fn locale(&self) -> crate::locale::Locale {
1466 crate::locale::Locale::invariant()
1467 }
1468
1469 fn workbook_sheet_count(&self) -> Option<usize> {
1471 None
1472 }
1473
1474 fn sheet_index_by_name(&self, _sheet: &str) -> Option<usize> {
1476 None
1477 }
1478
1479 fn current_sheet_index(&self, current_sheet: &str) -> Option<usize> {
1481 self.sheet_index_by_name(current_sheet)
1482 }
1483
1484 fn inspect_reference(
1486 &self,
1487 _reference: &ReferenceType,
1488 _current_sheet: &str,
1489 ) -> Result<Option<ReferenceInfo>, ExcelError> {
1490 Ok(None)
1491 }
1492
1493 fn formula_text_at_cell(&self, _cell: CellRef) -> Result<Option<String>, ExcelError> {
1495 Ok(None)
1496 }
1497
1498 fn clock(&self) -> &dyn crate::timezone::ClockProvider {
1507 #[cfg(feature = "system-clock")]
1508 {
1509 static DEFAULT_CLOCK: std::sync::OnceLock<crate::timezone::SystemClock> =
1510 std::sync::OnceLock::new();
1511 DEFAULT_CLOCK.get_or_init(|| {
1512 crate::timezone::SystemClock::new(crate::timezone::TimeZoneSpec::default())
1513 })
1514 }
1515 #[cfg(not(feature = "system-clock"))]
1516 {
1517 static DEFAULT_CLOCK: std::sync::OnceLock<crate::timezone::FixedClock> =
1518 std::sync::OnceLock::new();
1519 DEFAULT_CLOCK.get_or_init(|| {
1520 crate::timezone::FixedClock::new(
1521 chrono::DateTime::UNIX_EPOCH,
1522 crate::timezone::TimeZoneSpec::Utc,
1523 )
1524 })
1525 }
1526 }
1527
1528 fn timezone(&self) -> &crate::timezone::TimeZoneSpec {
1532 self.clock().timezone()
1533 }
1534
1535 fn volatile_level(&self) -> VolatileLevel {
1537 VolatileLevel::Always
1538 }
1539
1540 fn workbook_seed(&self) -> u64 {
1542 0xF0F0_D0D0_AAAA_5555
1543 }
1544
1545 fn recalc_epoch(&self) -> u64 {
1547 0
1548 }
1549
1550 fn used_rows_for_columns(
1555 &self,
1556 _sheet: &str,
1557 _start_col: u32,
1558 _end_col: u32,
1559 ) -> Option<(u32, u32)> {
1560 None
1561 }
1562
1563 fn used_cols_for_rows(
1566 &self,
1567 _sheet: &str,
1568 _start_row: u32,
1569 _end_row: u32,
1570 ) -> Option<(u32, u32)> {
1571 None
1572 }
1573
1574 fn sheet_bounds(&self, _sheet: &str) -> Option<(u32, u32)> {
1576 None
1577 }
1578
1579 fn data_snapshot_id(&self) -> u64 {
1581 0
1582 }
1583
1584 fn backend_caps(&self) -> BackendCaps {
1586 BackendCaps::default()
1587 }
1588
1589 fn date_system(&self) -> crate::engine::DateSystem {
1594 crate::engine::DateSystem::Excel1900
1595 }
1596
1597 fn build_lookup_index(
1600 &self,
1601 _view: &RangeView<'_>,
1602 _axis: LookupAxis,
1603 ) -> Option<std::sync::Arc<LookupIndex>> {
1604 None
1605 }
1606
1607 fn build_criteria_mask(
1610 &self,
1611 _view: &RangeView<'_>,
1612 _col_in_view: usize,
1613 _pred: &crate::args::CriteriaPredicate,
1614 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1615 None
1616 }
1617
1618 fn build_row_visibility_mask(
1621 &self,
1622 _view: &RangeView<'_>,
1623 _mode: VisibilityMaskMode,
1624 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1625 None
1626 }
1627}
1628
1629#[derive(Copy, Clone, Debug, Default)]
1631pub struct BackendCaps {
1632 pub streaming: bool,
1634 pub used_region: bool,
1636 pub write: bool,
1638 pub tables: bool,
1640 pub async_stream: bool,
1642}
1643
1644#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1647pub enum VolatileLevel {
1648 Always,
1650 OnRecalc,
1652 OnOpen,
1654}
1655
1656pub trait FunctionContext<'ctx> {
1658 fn locale(&self) -> crate::locale::Locale;
1659 fn timezone(&self) -> &crate::timezone::TimeZoneSpec;
1660 fn clock(&self) -> &dyn crate::timezone::ClockProvider;
1661 fn thread_pool(&self) -> Option<&std::sync::Arc<rayon::ThreadPool>>;
1662 fn cancellation_token(&self) -> Option<crate::engine::CancelToken>;
1668 fn chunk_hint(&self) -> Option<usize>;
1669
1670 fn current_sheet(&self) -> &str;
1672
1673 fn workbook_sheet_count(&self) -> Option<usize> {
1674 None
1675 }
1676
1677 fn sheet_index_by_name(&self, _sheet: &str) -> Option<usize> {
1678 None
1679 }
1680
1681 fn current_sheet_index(&self) -> Option<usize> {
1682 self.sheet_index_by_name(self.current_sheet())
1683 }
1684
1685 fn inspect_reference(
1686 &self,
1687 _reference: &ReferenceType,
1688 ) -> Result<Option<ReferenceInfo>, ExcelError> {
1689 Ok(None)
1690 }
1691
1692 fn formula_text_at_cell(&self, _cell: CellRef) -> Result<Option<String>, ExcelError> {
1693 Ok(None)
1694 }
1695
1696 fn volatile_level(&self) -> VolatileLevel;
1697 fn workbook_seed(&self) -> u64;
1698 fn recalc_epoch(&self) -> u64;
1699 fn current_cell(&self) -> Option<CellRef>;
1700
1701 fn resolve_range_view(
1703 &self,
1704 _reference: &ReferenceType,
1705 _current_sheet: &str,
1706 ) -> Result<RangeView<'ctx>, ExcelError>;
1707
1708 fn rng_for_current(&self, fn_salt: u64) -> rand::rngs::SmallRng {
1712 use crate::rng::{compose_seed, small_rng_from_lanes};
1713 let (sheet_id, row, col) = self
1714 .current_cell()
1715 .map(|c| (c.sheet_id as u32, c.coord.row(), c.coord.col()))
1716 .unwrap_or((0, 0, 0));
1717 let epoch = match self.volatile_level() {
1719 VolatileLevel::OnRecalc => self.recalc_epoch(),
1720 _ => 0,
1721 };
1722 let (l0, l1) = compose_seed(self.workbook_seed(), sheet_id, row, col, fn_salt, epoch);
1723 small_rng_from_lanes(l0, l1)
1724 }
1725
1726 fn date_system(&self) -> crate::engine::DateSystem {
1728 crate::engine::DateSystem::Excel1900
1729 }
1730
1731 fn get_lookup_index(
1734 &self,
1735 _view: &RangeView<'_>,
1736 _axis: LookupAxis,
1737 ) -> Option<std::sync::Arc<LookupIndex>> {
1738 None
1739 }
1740
1741 fn get_criteria_mask(
1744 &self,
1745 _view: &RangeView<'_>,
1746 _col_in_view: usize,
1747 _pred: &crate::args::CriteriaPredicate,
1748 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1749 None
1750 }
1751
1752 fn get_row_visibility_mask(
1754 &self,
1755 _view: &RangeView<'_>,
1756 _mode: VisibilityMaskMode,
1757 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1758 None
1759 }
1760}
1761
1762pub struct DefaultFunctionContext<'a> {
1764 pub base: &'a dyn EvaluationContext,
1765 pub current: Option<CellRef>,
1766 pub current_sheet: &'a str,
1767}
1768
1769impl<'a> DefaultFunctionContext<'a> {
1770 pub fn new(
1771 base: &'a dyn EvaluationContext,
1772 current: Option<CellRef>,
1773 current_sheet: &'a str,
1774 ) -> Self {
1775 Self {
1776 base,
1777 current,
1778 current_sheet,
1779 }
1780 }
1781
1782 pub fn new_with_sheet(
1783 base: &'a dyn EvaluationContext,
1784 current: Option<CellRef>,
1785 current_sheet: &'a str,
1786 ) -> Self {
1787 Self::new(base, current, current_sheet)
1788 }
1789}
1790
1791impl<'a> FunctionContext<'a> for DefaultFunctionContext<'a> {
1792 fn locale(&self) -> crate::locale::Locale {
1793 self.base.locale()
1794 }
1795
1796 fn current_sheet(&self) -> &str {
1797 self.current_sheet
1798 }
1799
1800 fn workbook_sheet_count(&self) -> Option<usize> {
1801 self.base.workbook_sheet_count()
1802 }
1803
1804 fn sheet_index_by_name(&self, sheet: &str) -> Option<usize> {
1805 self.base.sheet_index_by_name(sheet)
1806 }
1807
1808 fn current_sheet_index(&self) -> Option<usize> {
1809 self.base.current_sheet_index(self.current_sheet)
1810 }
1811
1812 fn inspect_reference(
1813 &self,
1814 reference: &ReferenceType,
1815 ) -> Result<Option<ReferenceInfo>, ExcelError> {
1816 self.base.inspect_reference(reference, self.current_sheet)
1817 }
1818
1819 fn formula_text_at_cell(&self, cell: CellRef) -> Result<Option<String>, ExcelError> {
1820 self.base.formula_text_at_cell(cell)
1821 }
1822
1823 fn timezone(&self) -> &crate::timezone::TimeZoneSpec {
1824 self.base.timezone()
1825 }
1826
1827 fn clock(&self) -> &dyn crate::timezone::ClockProvider {
1828 self.base.clock()
1829 }
1830 fn thread_pool(&self) -> Option<&std::sync::Arc<rayon::ThreadPool>> {
1831 self.base.thread_pool()
1832 }
1833 fn cancellation_token(&self) -> Option<crate::engine::CancelToken> {
1834 self.base.cancellation_token()
1835 }
1836 fn chunk_hint(&self) -> Option<usize> {
1837 self.base.chunk_hint()
1838 }
1839
1840 fn volatile_level(&self) -> VolatileLevel {
1841 self.base.volatile_level()
1842 }
1843 fn workbook_seed(&self) -> u64 {
1844 self.base.workbook_seed()
1845 }
1846 fn recalc_epoch(&self) -> u64 {
1847 self.base.recalc_epoch()
1848 }
1849 fn current_cell(&self) -> Option<CellRef> {
1850 self.current
1851 }
1852
1853 fn resolve_range_view(
1854 &self,
1855 reference: &ReferenceType,
1856 current_sheet: &str,
1857 ) -> Result<RangeView<'a>, ExcelError> {
1858 self.base.resolve_range_view(reference, current_sheet)
1859 }
1860
1861 fn date_system(&self) -> crate::engine::DateSystem {
1864 self.base.date_system()
1865 }
1866
1867 fn get_lookup_index(
1868 &self,
1869 view: &RangeView<'_>,
1870 axis: LookupAxis,
1871 ) -> Option<std::sync::Arc<LookupIndex>> {
1872 self.base.build_lookup_index(view, axis)
1873 }
1874
1875 fn get_criteria_mask(
1876 &self,
1877 view: &RangeView<'_>,
1878 col_in_view: usize,
1879 pred: &crate::args::CriteriaPredicate,
1880 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1881 self.base.build_criteria_mask(view, col_in_view, pred)
1882 }
1883
1884 fn get_row_visibility_mask(
1885 &self,
1886 view: &RangeView<'_>,
1887 mode: VisibilityMaskMode,
1888 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1889 self.base.build_row_visibility_mask(view, mode)
1890 }
1891}