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 AnnotatedScalar(LiteralValue, crate::format::FormatId),
112 Range(RangeView<'a>),
113 Callable(Arc<dyn CustomCallable>),
114}
115
116#[derive(Clone)]
122pub(crate) enum ResolvedArgument<'a> {
123 Range(RangeView<'a>),
124 ReferenceError(ExcelError),
125 Value(CalcValue<'a>),
126}
127
128impl std::fmt::Debug for ResolvedArgument<'_> {
129 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
130 match self {
131 Self::Range(view) => f.debug_tuple("Range").field(view).finish(),
132 Self::ReferenceError(error) => f.debug_tuple("ReferenceError").field(error).finish(),
133 Self::Value(value) => f.debug_tuple("Value").field(value).finish(),
134 }
135 }
136}
137
138impl<'a> std::fmt::Debug for CalcValue<'a> {
139 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140 match self {
141 CalcValue::Scalar(v) => f.debug_tuple("Scalar").field(v).finish(),
142 CalcValue::AnnotatedScalar(v, format) => f
143 .debug_tuple("AnnotatedScalar")
144 .field(v)
145 .field(format)
146 .finish(),
147 CalcValue::Range(rv) => {
148 let (r, c) = rv.dims();
149 f.debug_tuple("Range").field(&(r, c)).finish()
150 }
151 CalcValue::Callable(_) => f.write_str("Callable(<opaque>)"),
152 }
153 }
154}
155
156impl<'a> CalcValue<'a> {
157 pub fn into_literal(self) -> LiteralValue {
158 match self {
159 CalcValue::Scalar(s) | CalcValue::AnnotatedScalar(s, _) => s,
160 CalcValue::Range(rv) => {
161 let (rows, cols) = rv.dims();
162 if rows == 1 && cols == 1 {
163 rv.get_cell(0, 0)
164 } else {
165 let mut data = Vec::with_capacity(rows);
166 for row_idx in 0..rows {
167 let mut row = Vec::with_capacity(cols);
168 for col_idx in 0..cols {
169 row.push(rv.get_cell(row_idx, col_idx));
170 }
171 data.push(row);
172 }
173 LiteralValue::Array(data)
174 }
175 }
176 CalcValue::Callable(_) => LiteralValue::Error(
177 ExcelError::new(ExcelErrorKind::Calc).with_message("LAMBDA value must be invoked"),
178 ),
179 }
180 }
181
182 pub fn as_scalar(&self) -> Option<&LiteralValue> {
183 match self {
184 CalcValue::Scalar(s) | CalcValue::AnnotatedScalar(s, _) => Some(s),
185 _ => None,
186 }
187 }
188
189 pub fn format_id(&self) -> Option<crate::format::FormatId> {
190 match self {
191 CalcValue::AnnotatedScalar(_, format) => Some(*format),
192 _ => None,
193 }
194 }
195
196 pub fn with_format(self, format: Option<crate::format::FormatId>) -> Self {
197 let format = format.filter(|id| *id != crate::format::FormatId::GENERAL);
198 match (self, format) {
199 (CalcValue::Scalar(value) | CalcValue::AnnotatedScalar(value, _), Some(id)) => {
200 CalcValue::AnnotatedScalar(value, id)
201 }
202 (CalcValue::AnnotatedScalar(value, _), None) => CalcValue::Scalar(value),
203 (other, _) => other,
204 }
205 }
206
207 pub fn into_scalar_parts(self) -> (LiteralValue, Option<crate::format::FormatId>) {
208 match self {
209 CalcValue::Scalar(value) => (value, None),
210 CalcValue::AnnotatedScalar(value, format) => (value, Some(format)),
211 other => (other.into_literal(), None),
212 }
213 }
214
215 pub fn as_range(&self) -> Option<&RangeView<'a>> {
216 match self {
217 CalcValue::Range(r) => Some(r),
218 _ => None,
219 }
220 }
221
222 pub fn as_callable(&self) -> Option<&Arc<dyn CustomCallable>> {
223 match self {
224 CalcValue::Callable(c) => Some(c),
225 _ => None,
226 }
227 }
228
229 pub fn into_owned(self) -> LiteralValue {
230 self.into_literal()
231 }
232}
233
234impl From<CalcValue<'_>> for LiteralValue {
235 fn from(val: CalcValue<'_>) -> Self {
236 val.into_literal()
237 }
238}
239
240impl<'a> PartialEq<LiteralValue> for CalcValue<'a> {
241 fn eq(&self, other: &LiteralValue) -> bool {
242 match self {
243 CalcValue::Scalar(s) | CalcValue::AnnotatedScalar(s, _) => s == other,
244 CalcValue::Range(rv) => match other {
245 LiteralValue::Array(arr) => {
246 let (rows, cols) = rv.dims();
247 if arr.len() != rows {
248 return false;
249 }
250 for (r, row) in arr.iter().enumerate() {
251 if row.len() != cols {
252 return false;
253 }
254 for (c, cell) in row.iter().enumerate() {
255 if &rv.get_cell(r, c) != cell {
256 return false;
257 }
258 }
259 }
260 true
261 }
262 _ => {
263 let (rows, cols) = rv.dims();
264 rows == 1 && cols == 1 && &rv.get_cell(0, 0) == other
265 }
266 },
267 CalcValue::Callable(_) => false,
268 }
269 }
270}
271
272impl<'a> PartialEq<CalcValue<'a>> for LiteralValue {
273 fn eq(&self, other: &CalcValue<'a>) -> bool {
274 other == self
275 }
276}
277
278pub enum EvaluatedArg<'a> {
279 LiteralValue(CowValue<'a>),
280 Range(Box<dyn Range>),
281}
282
283enum ArgumentExpr<'a> {
284 Ast(&'a ASTNode),
285 Arena {
286 id: crate::engine::arena::AstNodeId,
287 data_store: &'a crate::engine::arena::DataStore,
288 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
289 },
290}
291
292pub struct ArgumentHandle<'a, 'b> {
293 expr: ArgumentExpr<'a>,
294 interp: &'a Interpreter<'b>,
295 cached_ast: std::cell::OnceCell<ASTNode>,
296 cached_ref: std::cell::OnceCell<ReferenceType>,
297 cached_reference_or_value:
298 std::cell::OnceCell<Result<crate::function::FunctionResolution<'b>, ExcelError>>,
299 cached_resolved: std::cell::OnceCell<Result<ResolvedArgument<'b>, ExcelError>>,
300 cached_value: std::cell::OnceCell<Result<crate::traits::CalcValue<'b>, ExcelError>>,
309}
310
311impl<'a, 'b> ArgumentHandle<'a, 'b> {
312 pub(crate) fn new(node: &'a ASTNode, interp: &'a Interpreter<'b>) -> Self {
313 Self {
314 expr: ArgumentExpr::Ast(node),
315 interp,
316 cached_ast: std::cell::OnceCell::new(),
317 cached_ref: std::cell::OnceCell::new(),
318 cached_reference_or_value: std::cell::OnceCell::new(),
319 cached_resolved: std::cell::OnceCell::new(),
320 cached_value: std::cell::OnceCell::new(),
321 }
322 }
323
324 pub(crate) fn new_arena(
325 id: crate::engine::arena::AstNodeId,
326 interp: &'a Interpreter<'b>,
327 data_store: &'a crate::engine::arena::DataStore,
328 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
329 ) -> Self {
330 Self {
331 expr: ArgumentExpr::Arena {
332 id,
333 data_store,
334 sheet_registry,
335 },
336 interp,
337 cached_ast: std::cell::OnceCell::new(),
338 cached_ref: std::cell::OnceCell::new(),
339 cached_reference_or_value: std::cell::OnceCell::new(),
340 cached_resolved: std::cell::OnceCell::new(),
341 cached_value: std::cell::OnceCell::new(),
342 }
343 }
344
345 pub(crate) fn date_system(&self) -> crate::engine::DateSystem {
351 self.interp.context.date_system()
352 }
353
354 pub fn is_omitted(&self) -> bool {
358 match &self.expr {
359 ArgumentExpr::Ast(node) => matches!(node.node_type, ASTNodeType::Omitted),
360 ArgumentExpr::Arena { id, data_store, .. } => matches!(
361 data_store.get_node(*id),
362 Some(crate::engine::arena::AstNodeData::Omitted)
363 ),
364 }
365 }
366
367 pub(crate) fn has_reference_semantics(&self) -> bool {
373 self.reference_attempt().is_some()
374 }
375
376 pub(crate) fn may_return_reference(&self) -> bool {
381 match &self.expr {
382 ArgumentExpr::Ast(node) => match &node.node_type {
383 ASTNodeType::Reference { reference, .. } => {
384 !matches!(reference, ReferenceType::NamedRange(name) if self.interp.resolve_local_name(name).is_some())
385 }
386 ASTNodeType::BinaryOp { op, .. } => op == ":",
387 ASTNodeType::Function { name, .. } => self
388 .interp
389 .context
390 .function_capabilities("", name)
391 .is_some_and(|caps| caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)),
392 _ => false,
393 },
394 ArgumentExpr::Arena { id, data_store, .. } => match data_store.get_node(*id) {
395 Some(crate::engine::arena::AstNodeData::Reference { ref_type, .. }) => !matches!(
396 ref_type,
397 crate::engine::arena::CompactRefType::NamedRange(name_id)
398 if self
399 .interp
400 .resolve_local_name(data_store.resolve_ast_string(*name_id))
401 .is_some()
402 ),
403 Some(crate::engine::arena::AstNodeData::BinaryOp { op_id, .. }) => {
404 data_store.resolve_ast_string(*op_id) == ":"
405 }
406 Some(crate::engine::arena::AstNodeData::Function { name_id, .. }) => self
407 .interp
408 .context
409 .function_capabilities("", data_store.resolve_ast_string(*name_id))
410 .is_some_and(|caps| caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)),
411 _ => false,
412 },
413 }
414 }
415
416 pub fn value(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
417 self.cached_value
418 .get_or_init(|| self.compute_value())
419 .clone()
420 }
421
422 pub(crate) fn value_for_text(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
428 if self.is_omitted() {
429 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Text(
430 String::new(),
431 )))
432 } else {
433 self.value()
434 }
435 }
436
437 pub(crate) fn resolve_once_for_text(&self) -> Result<ResolvedArgument<'b>, ExcelError> {
438 if self.is_omitted() {
439 Ok(ResolvedArgument::Value(crate::traits::CalcValue::Scalar(
440 LiteralValue::Text(String::new()),
441 )))
442 } else {
443 self.resolve_once()
444 }
445 }
446
447 fn compute_value(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
448 match &self.expr {
449 ArgumentExpr::Ast(node) => match &node.node_type {
450 ASTNodeType::Literal(v) => Ok(crate::traits::CalcValue::Scalar(v.clone())),
451 ASTNodeType::Omitted => {
454 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
455 }
456 _ => self.interp.evaluate_ast(node),
457 },
458 ArgumentExpr::Arena {
459 id,
460 data_store,
461 sheet_registry,
462 } => {
463 if matches!(
464 data_store.get_node(*id),
465 Some(crate::engine::arena::AstNodeData::Omitted)
466 ) {
467 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
468 } else {
469 self.interp
470 .evaluate_arena_ast(*id, data_store, sheet_registry)
471 }
472 }
473 }
474 }
475
476 pub fn value_with_env(
477 &self,
478 env: crate::interpreter::LocalEnv,
479 ) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
480 let scoped = self.interp.with_local_env(env);
481 match &self.expr {
482 ArgumentExpr::Ast(node) => match &node.node_type {
483 ASTNodeType::Literal(v) => Ok(crate::traits::CalcValue::Scalar(v.clone())),
484 ASTNodeType::Omitted => {
485 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
486 }
487 _ => scoped.evaluate_ast(node),
488 },
489 ArgumentExpr::Arena {
490 id,
491 data_store,
492 sheet_registry,
493 } => {
494 if matches!(
495 data_store.get_node(*id),
496 Some(crate::engine::arena::AstNodeData::Omitted)
497 ) {
498 Ok(crate::traits::CalcValue::Scalar(LiteralValue::Number(0.0)))
499 } else {
500 scoped.evaluate_arena_ast(*id, data_store, sheet_registry)
501 }
502 }
503 }
504 }
505
506 pub fn current_env(&self) -> crate::interpreter::LocalEnv {
507 self.interp.local_env().clone()
508 }
509
510 pub fn inline_array_literal(&self) -> Result<Option<Vec<Vec<LiteralValue>>>, ExcelError> {
511 match &self.expr {
512 ArgumentExpr::Ast(node) => match &node.node_type {
513 ASTNodeType::Literal(LiteralValue::Array(arr)) => Ok(Some(arr.clone())),
514 _ => Ok(None),
515 },
516 ArgumentExpr::Arena {
517 id,
518 data_store,
519 sheet_registry,
520 } => {
521 let node = data_store.get_node(*id).ok_or_else(|| {
522 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
523 })?;
524 match node {
525 crate::engine::arena::AstNodeData::Literal(vref) => {
526 match data_store.retrieve_value(*vref) {
527 LiteralValue::Array(arr) => Ok(Some(arr)),
528 _ => Ok(None),
529 }
530 }
531 _ => {
532 let _ = sheet_registry;
535 Ok(None)
536 }
537 }
538 }
539 }
540 }
541
542 fn reference_for_eval(&self) -> Result<ReferenceType, ExcelError> {
543 match &self.expr {
544 ArgumentExpr::Ast(node) => match &node.node_type {
545 ASTNodeType::Reference { reference, .. } => {
546 self.interp.reference_for_current_offset(reference)
547 }
548 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
549 self.interp.evaluate_ast_as_reference(node)
550 }
551 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
552 .with_message("Expected a reference (by-ref argument)")),
553 },
554 ArgumentExpr::Arena {
555 id,
556 data_store,
557 sheet_registry,
558 } => {
559 let node = data_store.get_node(*id).ok_or_else(|| {
560 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
561 })?;
562 match node {
563 crate::engine::arena::AstNodeData::Reference { ref_type, .. } => {
564 let reference = data_store
565 .reconstruct_reference_type_for_eval(ref_type, sheet_registry);
566 self.interp.reference_for_current_offset(&reference)
567 }
568 crate::engine::arena::AstNodeData::Function { .. }
569 | crate::engine::arena::AstNodeData::BinaryOp { .. } => self
570 .interp
571 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry),
572 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
573 .with_message("Expected a reference (by-ref argument)")),
574 }
575 }
576 }
577 }
578
579 fn function_resolution_attempt(
580 &self,
581 ) -> Option<Result<crate::function::FunctionResolution<'b>, ExcelError>> {
582 match &self.expr {
583 ArgumentExpr::Ast(node) => {
584 let ASTNodeType::Function { name, args } = &node.node_type else {
585 return None;
586 };
587 if !self
588 .interp
589 .context
590 .function_capabilities("", name)
591 .is_some_and(|caps| caps.contains(crate::function::FnCaps::RETURNS_REFERENCE))
592 {
593 return None;
594 }
595 let fun = match self.interp.context.get_function("", name) {
596 Some(fun) => fun,
597 None => {
598 return Some(Err(ExcelError::new(ExcelErrorKind::Name)
599 .with_message(format!("Unknown function: {name}"))));
600 }
601 };
602 let handles: Vec<_> = args
603 .iter()
604 .map(|arg| ArgumentHandle::new(arg, self.interp))
605 .collect();
606 let ctx = DefaultFunctionContext::new_with_sheet(
607 self.interp.context,
608 None,
609 self.interp.current_sheet(),
610 );
611 Some(fun.resolve_reference_or_value(&handles, &ctx, &|| self.value()))
612 }
613 ArgumentExpr::Arena {
614 id,
615 data_store,
616 sheet_registry,
617 } => {
618 let node = match data_store.get_node(*id) {
619 Some(node) => node,
620 None => {
621 return Some(Err(
622 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
623 ));
624 }
625 };
626 let crate::engine::arena::AstNodeData::Function { name_id, .. } = node else {
627 return None;
628 };
629 let name = data_store.resolve_ast_string(*name_id);
630 if !self
631 .interp
632 .context
633 .function_capabilities("", name)
634 .is_some_and(|caps| caps.contains(crate::function::FnCaps::RETURNS_REFERENCE))
635 {
636 return None;
637 }
638 let fun = match self.interp.context.get_function("", name) {
639 Some(fun) => fun,
640 None => {
641 return Some(Err(ExcelError::new(ExcelErrorKind::Name)
642 .with_message(format!("Unknown function: {name}"))));
643 }
644 };
645 let args = match data_store.get_args(*id) {
646 Some(args) => args,
647 None => {
648 return Some(Err(ExcelError::new(ExcelErrorKind::Value)
649 .with_message("Missing function args")));
650 }
651 };
652 let handles: Vec<_> = args
653 .iter()
654 .copied()
655 .map(|arg_id| {
656 ArgumentHandle::new_arena(arg_id, self.interp, data_store, sheet_registry)
657 })
658 .collect();
659 let ctx = DefaultFunctionContext::new_with_sheet(
660 self.interp.context,
661 None,
662 self.interp.current_sheet(),
663 );
664 Some(fun.resolve_reference_or_value(&handles, &ctx, &|| self.value()))
665 }
666 }
667 }
668
669 fn reference_attempt(&self) -> Option<Result<ReferenceType, ExcelError>> {
670 match &self.expr {
671 ArgumentExpr::Ast(node) => match &node.node_type {
672 ASTNodeType::Reference { reference, .. } => {
673 if let ReferenceType::NamedRange(name) = reference
677 && self.interp.resolve_local_name(name).is_some()
678 {
679 return None;
680 }
681 Some(self.interp.reference_for_current_offset(reference))
682 }
683 ASTNodeType::BinaryOp { op, .. } if op == ":" => {
684 Some(self.interp.evaluate_ast_as_reference(node))
685 }
686 ASTNodeType::Function { name, .. }
687 if self
688 .interp
689 .context
690 .function_capabilities("", name)
691 .is_some_and(|caps| {
692 caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)
693 }) =>
694 {
695 self.interp.try_evaluate_ast_as_reference(node)
696 }
697 _ => None,
698 },
699 ArgumentExpr::Arena {
700 id,
701 data_store,
702 sheet_registry,
703 } => {
704 let node = match data_store.get_node(*id) {
705 Some(node) => node,
706 None => {
707 return Some(Err(
708 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
709 ));
710 }
711 };
712 match node {
713 crate::engine::arena::AstNodeData::Reference { ref_type, .. } => {
714 if let crate::engine::arena::CompactRefType::NamedRange(name_id) = ref_type
716 && self
717 .interp
718 .resolve_local_name(data_store.resolve_ast_string(*name_id))
719 .is_some()
720 {
721 return None;
722 }
723 let reference = data_store
724 .reconstruct_reference_type_for_eval(ref_type, sheet_registry);
725 Some(self.interp.reference_for_current_offset(&reference))
726 }
727 crate::engine::arena::AstNodeData::BinaryOp { op_id, .. }
728 if data_store.resolve_ast_string(*op_id) == ":" =>
729 {
730 Some(self.interp.evaluate_arena_ast_as_reference(
731 *id,
732 data_store,
733 sheet_registry,
734 ))
735 }
736 crate::engine::arena::AstNodeData::Function { name_id, .. } => {
737 let name = data_store.resolve_ast_string(*name_id);
738 if self
739 .interp
740 .context
741 .function_capabilities("", name)
742 .is_some_and(|caps| {
743 caps.contains(crate::function::FnCaps::RETURNS_REFERENCE)
744 })
745 {
746 self.interp.try_evaluate_arena_ast_as_reference(
747 *id,
748 data_store,
749 sheet_registry,
750 )
751 } else {
752 None
753 }
754 }
755 _ => None,
756 }
757 }
758 }
759 }
760
761 pub(crate) fn resolve_reference_or_value(
762 &self,
763 ) -> Result<crate::function::FunctionResolution<'b>, ExcelError> {
764 let resolved = self
765 .cached_reference_or_value
766 .get_or_init(|| self.compute_reference_or_value())
767 .clone();
768 if let Ok(crate::function::FunctionResolution::Value(value)) = &resolved {
769 let _ = self.cached_value.set(Ok(value.clone()));
770 }
771 resolved
772 }
773
774 fn compute_reference_or_value(
775 &self,
776 ) -> Result<crate::function::FunctionResolution<'b>, ExcelError> {
777 if let Some(result) = self.function_resolution_attempt() {
778 return result;
779 }
780 if let Some(reference) = self.reference_attempt() {
781 return Ok(match reference {
782 Ok(reference) => crate::function::FunctionResolution::Reference(reference),
783 Err(error) => crate::function::FunctionResolution::ReferenceError(error),
784 });
785 }
786 self.value().map(crate::function::FunctionResolution::Value)
787 }
788
789 pub(crate) fn resolve_once(&self) -> Result<ResolvedArgument<'b>, ExcelError> {
795 self.cached_resolved
796 .get_or_init(|| self.compute_resolved_argument())
797 .clone()
798 }
799
800 fn with_context_cancel_token(&self, view: RangeView<'b>) -> RangeView<'b> {
801 match self.interp.context.cancellation_token() {
802 Some(token) => view.with_cancel_token(Some(token)),
803 None => view,
804 }
805 }
806
807 fn compute_resolved_argument(&self) -> Result<ResolvedArgument<'b>, ExcelError> {
808 let value = match self.resolve_reference_or_value()? {
809 crate::function::FunctionResolution::Reference(reference) => {
810 return match self
811 .interp
812 .context
813 .resolve_range_view(&reference, self.interp.current_sheet())
814 {
815 Ok(view) => Ok(ResolvedArgument::Range(
816 self.with_context_cancel_token(view),
817 )),
818 Err(error) if error.kind == ExcelErrorKind::Cancelled => Err(error),
819 Err(error) => Ok(ResolvedArgument::ReferenceError(error)),
820 };
821 }
822 crate::function::FunctionResolution::ReferenceError(error)
823 if error.kind == ExcelErrorKind::Cancelled =>
824 {
825 return Err(error);
826 }
827 crate::function::FunctionResolution::ReferenceError(error) => {
828 return Ok(ResolvedArgument::ReferenceError(error));
829 }
830 crate::function::FunctionResolution::Value(value) => value,
831 };
832
833 match value {
834 CalcValue::Range(view) => Ok(ResolvedArgument::Range(
835 self.with_context_cancel_token(view),
836 )),
837 CalcValue::Scalar(LiteralValue::Array(rows)) => {
838 let view = RangeView::try_from_owned_rows(
839 rows,
840 self.interp.context.date_system(),
841 self.interp.context.cancellation_token(),
842 )?;
843 Ok(ResolvedArgument::Range(view))
844 }
845 other => Ok(ResolvedArgument::Value(other)),
846 }
847 }
848
849 pub fn range(&self) -> Result<Box<dyn Range>, ExcelError> {
850 match &self.expr {
851 ArgumentExpr::Ast(node) => match &node.node_type {
852 ASTNodeType::Reference { reference, .. } => {
853 let reference = self.interp.reference_for_current_offset(reference)?;
855 let view = self
856 .interp
857 .context
858 .resolve_range_view(&reference, self.interp.current_sheet())?;
859 let (rows, cols) = view.dims();
860 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
861 view.for_each_row(&mut |row| {
862 let row_data: Vec<LiteralValue> = (0..cols)
863 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
864 .collect();
865 out.push(row_data);
866 Ok(())
867 })?;
868 Ok(Box::new(InMemoryRange::new(out)))
869 }
870 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
871 let reference = self.reference_for_eval()?;
872 let view = self
873 .interp
874 .context
875 .resolve_range_view(&reference, self.interp.current_sheet())?;
876 let (rows, cols) = view.dims();
877 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
878 view.for_each_row(&mut |row| {
879 let row_data: Vec<LiteralValue> = (0..cols)
880 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
881 .collect();
882 out.push(row_data);
883 Ok(())
884 })?;
885 Ok(Box::new(InMemoryRange::new(out)))
886 }
887 ASTNodeType::Array(rows) => {
888 let mut materialized = Vec::new();
889 for row in rows {
890 let mut materialized_row = Vec::new();
891 for cell in row {
892 materialized_row.push(self.interp.evaluate_ast(cell)?.into_literal());
893 }
894 materialized.push(materialized_row);
895 }
896 Ok(Box::new(InMemoryRange::new(materialized)))
897 }
898 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
899 .with_message(format!("Expected a range, got {:?}", node.node_type))),
900 },
901 ArgumentExpr::Arena { id, data_store, .. } => {
902 let node = data_store.get_node(*id).ok_or_else(|| {
903 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
904 })?;
905
906 match node {
907 crate::engine::arena::AstNodeData::Reference { .. }
908 | crate::engine::arena::AstNodeData::Function { .. }
909 | crate::engine::arena::AstNodeData::BinaryOp { .. } => {
910 let reference = self.reference_for_eval()?;
911 let view = self
912 .interp
913 .context
914 .resolve_range_view(&reference, self.interp.current_sheet())?;
915 let (rows, cols) = view.dims();
916 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
917 view.for_each_row(&mut |row| {
918 let row_data: Vec<LiteralValue> = (0..cols)
919 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
920 .collect();
921 out.push(row_data);
922 Ok(())
923 })?;
924 Ok(Box::new(InMemoryRange::new(out)))
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 let rows_usize = rows as usize;
932 let cols_usize = cols as usize;
933 let mut materialized: Vec<Vec<LiteralValue>> =
934 Vec::with_capacity(rows_usize);
935 for r in 0..rows_usize {
936 let mut row = Vec::with_capacity(cols_usize);
937 for c in 0..cols_usize {
938 let idx = r * cols_usize + c;
939 let elem_id = elements.get(idx).copied().ok_or_else(|| {
940 ExcelError::new(ExcelErrorKind::Value)
941 .with_message("Invalid array")
942 })?;
943 let v = self.interp.evaluate_arena_ast(
944 elem_id,
945 data_store,
946 self.sheet_registry(),
947 )?;
948 row.push(v.into_literal());
949 }
950 materialized.push(row);
951 }
952 Ok(Box::new(InMemoryRange::new(materialized)))
953 }
954 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
955 .with_message("Argument cannot be interpreted as a range.")),
956 }
957 }
958 }
959 }
960
961 fn sheet_registry(&self) -> &crate::engine::sheet_registry::SheetRegistry {
962 match &self.expr {
963 ArgumentExpr::Ast(_) => {
964 unreachable!("sheet_registry only used for arena ArgumentHandle")
966 }
967 ArgumentExpr::Arena { sheet_registry, .. } => sheet_registry,
968 }
969 }
970
971 pub fn range_view(&self) -> Result<RangeView<'b>, ExcelError> {
979 match self.resolve_once()? {
980 ResolvedArgument::Range(view) => Ok(view),
981 ResolvedArgument::ReferenceError(error) => Err(error),
984 ResolvedArgument::Value(CalcValue::Range(view)) => {
989 Ok(self.with_context_cancel_token(view))
990 }
991 ResolvedArgument::Value(CalcValue::Scalar(LiteralValue::Array(rows))) => {
992 RangeView::try_from_owned_rows(
993 rows,
994 self.interp.context.date_system(),
995 self.interp.context.cancellation_token(),
996 )
997 }
998 ResolvedArgument::Value(_) => Err(ExcelError::new(ExcelErrorKind::Ref)
999 .with_message("Argument cannot be interpreted as a range.")),
1000 }
1001 }
1002
1003 pub fn range_view_or_scalar(&self) -> Result<RangeView<'b>, ExcelError> {
1023 match self.resolve_once()? {
1024 ResolvedArgument::Range(view) => Ok(view),
1025 ResolvedArgument::ReferenceError(error) => Err(error),
1026 ResolvedArgument::Value(CalcValue::Range(view)) => {
1027 Ok(self.with_context_cancel_token(view))
1028 }
1029 ResolvedArgument::Value(CalcValue::Scalar(LiteralValue::Array(rows))) => {
1030 RangeView::try_from_owned_rows(
1031 rows,
1032 self.interp.context.date_system(),
1033 self.interp.context.cancellation_token(),
1034 )
1035 }
1036 ResolvedArgument::Value(CalcValue::Scalar(LiteralValue::Error(error))) => Err(error),
1039 ResolvedArgument::Value(
1040 CalcValue::Scalar(scalar) | CalcValue::AnnotatedScalar(scalar, _),
1041 ) => RangeView::try_from_owned_rows(
1042 vec![vec![scalar]],
1043 self.interp.context.date_system(),
1044 self.interp.context.cancellation_token(),
1045 ),
1046 ResolvedArgument::Value(CalcValue::Callable(_)) => {
1048 Err(ExcelError::new(ExcelErrorKind::Ref)
1049 .with_message("Argument cannot be interpreted as a range."))
1050 }
1051 }
1052 }
1053
1054 pub fn value_or_range(&self) -> Result<EvaluatedArg<'_>, ExcelError> {
1055 self.range().map(EvaluatedArg::Range).or_else(|_| {
1056 self.value()
1057 .map(|cv| EvaluatedArg::LiteralValue(Cow::Owned(cv.into_literal())))
1058 })
1059 }
1060
1061 pub fn lazy_values_owned(
1066 &'a self,
1067 ) -> Result<Box<dyn Iterator<Item = LiteralValue> + 'a>, ExcelError> {
1068 match &self.expr {
1069 ArgumentExpr::Ast(node) => match &node.node_type {
1070 ASTNodeType::Reference { .. } => {
1071 let view = self.range_view()?;
1072 let mut values: Vec<LiteralValue> = Vec::new();
1073 view.for_each_cell(&mut |v| {
1074 values.push(v.clone());
1075 Ok(())
1076 })?;
1077 Ok(Box::new(values.into_iter()))
1078 }
1079 ASTNodeType::Array(rows) => {
1080 struct ArrayEvalIter<'a, 'b> {
1081 rows: &'a [Vec<ASTNode>],
1082 r: usize,
1083 c: usize,
1084 interp: &'a Interpreter<'b>,
1085 }
1086 impl<'a, 'b> Iterator for ArrayEvalIter<'a, 'b> {
1087 type Item = LiteralValue;
1088 fn next(&mut self) -> Option<Self::Item> {
1089 if self.rows.is_empty() {
1090 return None;
1091 }
1092 let rows = self.rows;
1093 let mut r = self.r;
1094 let mut c = self.c;
1095 if r >= rows.len() {
1096 return None;
1097 }
1098 let node = &rows[r][c];
1099 c += 1;
1101 if c >= rows[r].len() {
1102 r += 1;
1103 c = 0;
1104 }
1105 self.r = r;
1106 self.c = c;
1107 match self.interp.evaluate_ast(node) {
1108 Ok(cv) => Some(cv.into_literal()),
1109 Err(e) => Some(LiteralValue::Error(e)),
1110 }
1111 }
1112 }
1113 let it = ArrayEvalIter {
1114 rows,
1115 r: 0,
1116 c: 0,
1117 interp: self.interp,
1118 };
1119 Ok(Box::new(it))
1120 }
1121 _ => {
1122 let v = self.value()?.into_literal();
1124 Ok(Box::new(std::iter::once(v)))
1125 }
1126 },
1127 ArgumentExpr::Arena {
1128 id,
1129 data_store,
1130 sheet_registry,
1131 } => {
1132 let node = data_store.get_node(*id).ok_or_else(|| {
1133 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
1134 })?;
1135
1136 match node {
1137 crate::engine::arena::AstNodeData::Reference { .. } => {
1138 let view = self.range_view()?;
1139 let mut values: Vec<LiteralValue> = Vec::new();
1140 view.for_each_cell(&mut |v| {
1141 values.push(v.clone());
1142 Ok(())
1143 })?;
1144 Ok(Box::new(values.into_iter()))
1145 }
1146 crate::engine::arena::AstNodeData::Array { .. } => {
1147 let (rows, cols, elements) =
1148 data_store.get_array_elems(*id).ok_or_else(|| {
1149 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
1150 })?;
1151
1152 struct ArenaArrayEvalIter<'a, 'b> {
1153 elements: &'a [crate::engine::arena::AstNodeId],
1154 idx: usize,
1155 interp: &'a Interpreter<'b>,
1156 data_store: &'a crate::engine::arena::DataStore,
1157 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
1158 }
1159
1160 impl<'a, 'b> Iterator for ArenaArrayEvalIter<'a, 'b> {
1161 type Item = LiteralValue;
1162
1163 fn next(&mut self) -> Option<Self::Item> {
1164 let id = self.elements.get(self.idx).copied()?;
1165 self.idx += 1;
1166 match self.interp.evaluate_arena_ast(
1167 id,
1168 self.data_store,
1169 self.sheet_registry,
1170 ) {
1171 Ok(cv) => Some(cv.into_literal()),
1172 Err(e) => Some(LiteralValue::Error(e)),
1173 }
1174 }
1175 }
1176
1177 let _ = (rows, cols);
1178 let it = ArenaArrayEvalIter {
1179 elements,
1180 idx: 0,
1181 interp: self.interp,
1182 data_store,
1183 sheet_registry,
1184 };
1185 Ok(Box::new(it))
1186 }
1187 _ => {
1188 let v = self
1189 .interp
1190 .evaluate_arena_ast(*id, data_store, sheet_registry)?;
1191 Ok(Box::new(std::iter::once(v.into_literal())))
1192 }
1193 }
1194 }
1195 }
1196 }
1197
1198 pub fn ast(&self) -> &ASTNode {
1199 match &self.expr {
1200 ArgumentExpr::Ast(node) => node,
1201 ArgumentExpr::Arena {
1202 id,
1203 data_store,
1204 sheet_registry,
1205 } => self.cached_ast.get_or_init(|| {
1206 data_store
1207 .retrieve_ast(*id, sheet_registry)
1208 .unwrap_or_else(|| ASTNode {
1209 node_type: ASTNodeType::Literal(LiteralValue::Error(
1210 ExcelError::new(ExcelErrorKind::Value)
1211 .with_message("Missing formula AST"),
1212 )),
1213 source_token: None,
1214 contains_volatile: false,
1215 })
1216 }),
1217 }
1218 }
1219
1220 pub fn as_reference(&self) -> Result<&ReferenceType, ExcelError> {
1223 match &self.expr {
1224 ArgumentExpr::Ast(node) => match &node.node_type {
1225 ASTNodeType::Reference { reference, .. } => Ok(reference),
1226 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1227 .with_message("Expected a reference (by-ref argument)")),
1228 },
1229 ArgumentExpr::Arena { .. } => {
1230 let reference = self.reference_for_eval()?;
1231 Ok(self.cached_ref.get_or_init(|| reference))
1232 }
1233 }
1234 }
1235
1236 pub fn as_reference_or_eval(&self) -> Result<ReferenceType, ExcelError> {
1239 match &self.expr {
1240 ArgumentExpr::Ast(node) => match &node.node_type {
1241 ASTNodeType::Reference { reference, .. } => {
1242 self.interp.reference_for_current_offset(reference)
1243 }
1244 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
1245 self.interp.evaluate_ast_as_reference(node)
1246 }
1247 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1248 .with_message("Argument is not a reference")),
1249 },
1250 ArgumentExpr::Arena {
1251 id,
1252 data_store,
1253 sheet_registry,
1254 } => {
1255 let node = data_store.get_node(*id).ok_or_else(|| {
1256 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
1257 })?;
1258
1259 match node {
1260 crate::engine::arena::AstNodeData::Reference { .. } => {
1261 self.reference_for_eval()
1262 }
1263 crate::engine::arena::AstNodeData::Function { .. }
1264 | crate::engine::arena::AstNodeData::BinaryOp { .. } => self
1265 .interp
1266 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry),
1267 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
1268 .with_message("Argument is not a reference")),
1269 }
1270 }
1271 }
1272 }
1273
1274 pub fn matches_kind(&self, k: formualizer_common::ArgKind) -> Result<bool, ExcelError> {
1276 Ok(match k {
1277 formualizer_common::ArgKind::Any => true,
1278 formualizer_common::ArgKind::Range => self.range().is_ok(),
1279 formualizer_common::ArgKind::Number => matches!(
1280 self.value()?.into_literal(),
1281 LiteralValue::Number(_) | LiteralValue::Int(_)
1282 ),
1283 formualizer_common::ArgKind::Text => {
1284 matches!(self.value()?.into_literal(), LiteralValue::Text(_))
1285 }
1286 formualizer_common::ArgKind::Logical => {
1287 matches!(self.value()?.into_literal(), LiteralValue::Boolean(_))
1288 }
1289 })
1290 }
1291}
1292
1293#[derive(Debug, Clone)]
1295pub struct InMemoryRange {
1296 data: Vec<Vec<LiteralValue>>,
1297}
1298impl InMemoryRange {
1299 pub fn new(d: Vec<Vec<LiteralValue>>) -> Self {
1300 Self { data: d }
1301 }
1302}
1303impl Range for InMemoryRange {
1304 fn get(&self, r: usize, c: usize) -> Result<LiteralValue, ExcelError> {
1305 Ok(self
1306 .data
1307 .get(r)
1308 .and_then(|row| row.get(c))
1309 .cloned()
1310 .unwrap_or(LiteralValue::Empty))
1311 }
1312 fn dimensions(&self) -> (usize, usize) {
1313 (self.data.len(), self.data.first().map_or(0, |r| r.len()))
1314 }
1315 fn as_any(&self) -> &dyn Any {
1316 self
1317 }
1318}
1319
1320pub trait Table: Debug + Send + Sync {
1323 fn get_cell(&self, row: usize, column: &str) -> Result<LiteralValue, ExcelError>;
1324 fn get_column(&self, column: &str) -> Result<Box<dyn Range>, ExcelError>;
1325 fn columns(&self) -> Vec<String> {
1327 vec![]
1328 }
1329 fn data_height(&self) -> usize {
1331 0
1332 }
1333 fn has_headers(&self) -> bool {
1335 false
1336 }
1337 fn has_totals(&self) -> bool {
1339 false
1340 }
1341 fn headers_row(&self) -> Option<Box<dyn Range>> {
1343 None
1344 }
1345 fn totals_row(&self) -> Option<Box<dyn Range>> {
1347 None
1348 }
1349 fn data_body(&self) -> Option<Box<dyn Range>> {
1351 None
1352 }
1353 fn clone_box(&self) -> Box<dyn Table>;
1354}
1355impl Table for Box<dyn Table> {
1356 fn get_cell(&self, r: usize, c: &str) -> Result<LiteralValue, ExcelError> {
1357 (**self).get_cell(r, c)
1358 }
1359 fn get_column(&self, c: &str) -> Result<Box<dyn Range>, ExcelError> {
1360 (**self).get_column(c)
1361 }
1362 fn columns(&self) -> Vec<String> {
1363 (**self).columns()
1364 }
1365 fn data_height(&self) -> usize {
1366 (**self).data_height()
1367 }
1368 fn has_headers(&self) -> bool {
1369 (**self).has_headers()
1370 }
1371 fn has_totals(&self) -> bool {
1372 (**self).has_totals()
1373 }
1374 fn headers_row(&self) -> Option<Box<dyn Range>> {
1375 (**self).headers_row()
1376 }
1377 fn totals_row(&self) -> Option<Box<dyn Range>> {
1378 (**self).totals_row()
1379 }
1380 fn data_body(&self) -> Option<Box<dyn Range>> {
1381 (**self).data_body()
1382 }
1383 fn clone_box(&self) -> Box<dyn Table> {
1384 (**self).clone_box()
1385 }
1386}
1387
1388pub trait ReferenceResolver: Send + Sync {
1391 fn resolve_cell_reference(
1392 &self,
1393 sheet: Option<&str>,
1394 row: u32,
1395 col: u32,
1396 ) -> Result<LiteralValue, ExcelError>;
1397}
1398pub trait RangeResolver: Send + Sync {
1399 fn resolve_range_reference(
1400 &self,
1401 sheet: Option<&str>,
1402 sr: Option<u32>,
1403 sc: Option<u32>,
1404 er: Option<u32>,
1405 ec: Option<u32>,
1406 ) -> Result<Box<dyn Range>, ExcelError>;
1407}
1408pub trait NamedRangeResolver: Send + Sync {
1409 fn resolve_named_range_reference(
1410 &self,
1411 name: &str,
1412 ) -> Result<Vec<Vec<LiteralValue>>, ExcelError>;
1413}
1414pub trait TableResolver: Send + Sync {
1415 fn resolve_table_reference(
1416 &self,
1417 tref: &formualizer_parse::parser::TableReference,
1418 ) -> Result<Box<dyn Table>, ExcelError>;
1419}
1420
1421pub trait SourceResolver: Send + Sync {
1422 fn source_scalar_version(&self, _name: &str) -> Option<u64> {
1423 None
1424 }
1425
1426 fn resolve_source_scalar(&self, name: &str) -> Result<LiteralValue, ExcelError> {
1427 Err(ExcelError::new(ExcelErrorKind::NImpl)
1428 .with_message(format!("Source scalar not supported: {name}")))
1429 }
1430
1431 fn source_table_version(&self, _name: &str) -> Option<u64> {
1432 None
1433 }
1434
1435 fn resolve_source_table(&self, name: &str) -> Result<Box<dyn Table>, ExcelError> {
1436 Err(ExcelError::new(ExcelErrorKind::NImpl)
1437 .with_message(format!("Source table not supported: {name}")))
1438 }
1439}
1440
1441pub trait Resolver: ReferenceResolver + RangeResolver + NamedRangeResolver + TableResolver {
1442 fn resolve_range_like(&self, r: &ReferenceType) -> Result<Box<dyn Range>, ExcelError> {
1443 match r {
1444 ReferenceType::Range {
1445 sheet,
1446 start_row,
1447 start_col,
1448 end_row,
1449 end_col,
1450 ..
1451 } => self.resolve_range_reference(
1452 sheet.as_deref(),
1453 *start_row,
1454 *start_col,
1455 *end_row,
1456 *end_col,
1457 ),
1458 ReferenceType::External(_) => Err(ExcelError::new(ExcelErrorKind::NImpl)
1459 .with_message("External references are not supported by Resolver".to_string())),
1460 ReferenceType::Table(tref) => {
1461 let t = self.resolve_table_reference(tref)?;
1462 match &tref.specifier {
1463 Some(TableSpecifier::Column(c)) => t.get_column(c),
1464 Some(TableSpecifier::ColumnRange(start, end)) => {
1465 let cols = t.columns();
1467 let start_key = start.to_lowercase();
1468 let end_key = end.to_lowercase();
1469 let start_idx = cols.iter().position(|n| n.to_lowercase() == start_key);
1470 let end_idx = cols.iter().position(|n| n.to_lowercase() == end_key);
1471 if let (Some(mut si), Some(mut ei)) = (start_idx, end_idx) {
1472 if si > ei {
1473 std::mem::swap(&mut si, &mut ei);
1474 }
1475 let h = t.data_height();
1477 let w = ei - si + 1;
1478 let mut rows = vec![vec![LiteralValue::Empty; w]; h];
1479 for (offset, ci) in (si..=ei).enumerate() {
1480 let cname = &cols[ci];
1481 let col_range = t.get_column(cname)?;
1482 let (rh, _) = col_range.dimensions();
1483 for (r, row) in rows.iter_mut().enumerate().take(h.min(rh)) {
1484 row[offset] = col_range.get(r, 0)?;
1485 }
1486 }
1487 Ok(Box::new(InMemoryRange::new(rows)))
1488 } else {
1489 Err(ExcelError::new(ExcelErrorKind::Ref).with_message(
1490 "Column range refers to unknown column(s)".to_string(),
1491 ))
1492 }
1493 }
1494 Some(TableSpecifier::SpecialItem(
1495 formualizer_parse::parser::SpecialItem::Headers,
1496 )) => {
1497 if let Some(h) = t.headers_row() {
1498 Ok(h)
1499 } else {
1500 Ok(Box::new(InMemoryRange::new(vec![])))
1501 }
1502 }
1503 Some(TableSpecifier::SpecialItem(
1504 formualizer_parse::parser::SpecialItem::Totals,
1505 )) => {
1506 if let Some(tr) = t.totals_row() {
1507 Ok(tr)
1508 } else {
1509 Ok(Box::new(InMemoryRange::new(vec![])))
1510 }
1511 }
1512 Some(TableSpecifier::SpecialItem(
1513 formualizer_parse::parser::SpecialItem::Data,
1514 )) => {
1515 if let Some(body) = t.data_body() {
1516 Ok(body)
1517 } else {
1518 Ok(Box::new(InMemoryRange::new(vec![])))
1519 }
1520 }
1521 Some(TableSpecifier::SpecialItem(
1522 formualizer_parse::parser::SpecialItem::All,
1523 )) => {
1524 let mut out: Vec<Vec<LiteralValue>> = Vec::new();
1526 if let Some(h) = t.headers_row() {
1527 out.extend(h.iter_rows());
1528 }
1529 if let Some(body) = t.data_body() {
1530 out.extend(body.iter_rows());
1531 }
1532 if let Some(tr) = t.totals_row() {
1533 out.extend(tr.iter_rows());
1534 }
1535 Ok(Box::new(InMemoryRange::new(out)))
1536 }
1537 Some(TableSpecifier::SpecialItem(
1538 formualizer_parse::parser::SpecialItem::ThisRow,
1539 )) => Err(ExcelError::new(ExcelErrorKind::NImpl).with_message(
1540 "@ (This Row) requires table-aware context; not yet supported".to_string(),
1541 )),
1542 Some(TableSpecifier::All) => {
1543 let mut out: Vec<Vec<LiteralValue>> = Vec::new();
1545 if let Some(h) = t.headers_row() {
1546 out.extend(h.iter_rows());
1547 }
1548 if let Some(body) = t.data_body() {
1549 out.extend(body.iter_rows());
1550 }
1551 if let Some(tr) = t.totals_row() {
1552 out.extend(tr.iter_rows());
1553 }
1554 Ok(Box::new(InMemoryRange::new(out)))
1555 }
1556 Some(TableSpecifier::Data) => {
1557 if let Some(body) = t.data_body() {
1558 Ok(body)
1559 } else {
1560 Ok(Box::new(InMemoryRange::new(vec![])))
1561 }
1562 }
1563 Some(TableSpecifier::Combination(_)) => Err(ExcelError::new(
1565 ExcelErrorKind::NImpl,
1566 )
1567 .with_message("Complex structured references not yet supported".to_string())),
1568 Some(TableSpecifier::Row(_)) => Err(ExcelError::new(ExcelErrorKind::NImpl)
1569 .with_message("Row selectors (@/index) not yet supported".to_string())),
1570 Some(TableSpecifier::Headers) | Some(TableSpecifier::Totals) => {
1571 Err(ExcelError::new(ExcelErrorKind::NImpl).with_message(
1572 "Legacy Headers/Totals variants not used; use SpecialItem".to_string(),
1573 ))
1574 }
1575 None => Err(ExcelError::new(ExcelErrorKind::Ref).with_message(
1576 "Table reference without specifier is unsupported".to_string(),
1577 )),
1578 }
1579 }
1580 ReferenceType::NamedRange(n) => {
1581 let v = self.resolve_named_range_reference(n)?;
1582 Ok(Box::new(InMemoryRange::new(v)))
1583 }
1584 ReferenceType::Cell {
1585 sheet, row, col, ..
1586 } => {
1587 let v = self.resolve_cell_reference(sheet.as_deref(), *row, *col)?;
1588 Ok(Box::new(InMemoryRange::new(vec![vec![v]])))
1589 }
1590 ReferenceType::Cell3D { .. } | ReferenceType::Range3D { .. } => {
1591 Err(ExcelError::new(ExcelErrorKind::NImpl)
1592 .with_message("3D references are not yet supported".to_string()))
1593 }
1594 }
1595 }
1596}
1597
1598pub trait FunctionProvider: Send + Sync {
1601 fn get_function(&self, ns: &str, name: &str) -> Option<Arc<dyn Function>>;
1602
1603 #[doc(hidden)]
1604 fn get_function_for_planning(&self, _ns: &str, _name: &str) -> Option<Arc<dyn Function>> {
1605 None
1606 }
1607
1608 #[doc(hidden)]
1611 fn planning_semantic_revision(&self) -> Option<u64> {
1612 None
1613 }
1614
1615 #[doc(hidden)]
1616 fn function_capabilities(&self, ns: &str, name: &str) -> Option<crate::function::FnCaps> {
1617 self.get_function(ns, name).map(|function| function.caps())
1618 }
1619
1620 fn function_semantic_identity(
1621 &self,
1622 ns: &str,
1623 name: &str,
1624 arity: usize,
1625 ) -> Option<crate::function_contract::FunctionSemanticIdentity> {
1626 crate::function_registry::resolve_semantic_identity(self, ns, name, arity)
1627 }
1628}
1629
1630pub trait EvaluationContext: Resolver + FunctionProvider + SourceResolver {
1631 fn thread_pool(&self) -> Option<&Arc<rayon::ThreadPool>> {
1634 None
1635 }
1636
1637 fn cancellation_token(&self) -> Option<crate::engine::CancelToken> {
1644 None
1645 }
1646
1647 fn chunk_hint(&self) -> Option<usize> {
1649 None
1650 }
1651
1652 fn resolve_range_view<'c>(
1655 &'c self,
1656 _reference: &ReferenceType,
1657 _current_sheet: &str,
1658 ) -> Result<RangeView<'c>, ExcelError> {
1659 Err(ExcelError::new(ExcelErrorKind::NImpl))
1660 }
1661
1662 fn resolve_cell_reference_value(
1667 &self,
1668 sheet: Option<&str>,
1669 row: u32,
1670 col: u32,
1671 current_sheet: &str,
1672 ) -> Result<LiteralValue, ExcelError> {
1673 let reference = ReferenceType::Cell {
1674 sheet: sheet.map(str::to_string),
1675 row,
1676 col,
1677 row_abs: true,
1678 col_abs: true,
1679 };
1680 let view = self.resolve_range_view(&reference, current_sheet)?;
1681 Ok(view.as_1x1().unwrap_or(LiteralValue::Empty))
1682 }
1683
1684 fn resolve_cell_format(
1686 &self,
1687 _sheet: Option<&str>,
1688 _row: u32,
1689 _col: u32,
1690 _current_sheet: &str,
1691 ) -> Option<crate::format::FormatId> {
1692 None
1693 }
1694
1695 fn format_class(
1697 &self,
1698 format: crate::format::FormatId,
1699 ) -> Option<formualizer_common::numfmt::FormatClass> {
1700 formualizer_common::numfmt::NumberFormat::builtin(format.0)
1701 .map(|format| format.class().clone())
1702 }
1703
1704 fn record_cell_derived_format(
1706 &self,
1707 _sheet: &str,
1708 _row: u32,
1709 _col: u32,
1710 _format: Option<crate::format::FormatId>,
1711 ) {
1712 }
1713
1714 fn locale(&self) -> crate::locale::Locale {
1716 crate::locale::Locale::invariant()
1717 }
1718
1719 fn workbook_sheet_count(&self) -> Option<usize> {
1721 None
1722 }
1723
1724 fn sheet_index_by_name(&self, _sheet: &str) -> Option<usize> {
1726 None
1727 }
1728
1729 fn current_sheet_index(&self, current_sheet: &str) -> Option<usize> {
1731 self.sheet_index_by_name(current_sheet)
1732 }
1733
1734 fn inspect_reference(
1736 &self,
1737 _reference: &ReferenceType,
1738 _current_sheet: &str,
1739 ) -> Result<Option<ReferenceInfo>, ExcelError> {
1740 Ok(None)
1741 }
1742
1743 fn formula_text_at_cell(&self, _cell: CellRef) -> Result<Option<String>, ExcelError> {
1745 Ok(None)
1746 }
1747
1748 fn clock(&self) -> &dyn crate::timezone::ClockProvider {
1757 #[cfg(feature = "system-clock")]
1758 {
1759 static DEFAULT_CLOCK: std::sync::OnceLock<crate::timezone::SystemClock> =
1760 std::sync::OnceLock::new();
1761 DEFAULT_CLOCK.get_or_init(|| {
1762 crate::timezone::SystemClock::new(crate::timezone::TimeZoneSpec::default())
1763 })
1764 }
1765 #[cfg(not(feature = "system-clock"))]
1766 {
1767 static DEFAULT_CLOCK: std::sync::OnceLock<crate::timezone::FixedClock> =
1768 std::sync::OnceLock::new();
1769 DEFAULT_CLOCK.get_or_init(|| {
1770 crate::timezone::FixedClock::new(
1771 chrono::DateTime::UNIX_EPOCH,
1772 crate::timezone::TimeZoneSpec::Utc,
1773 )
1774 })
1775 }
1776 }
1777
1778 fn timezone(&self) -> &crate::timezone::TimeZoneSpec {
1782 self.clock().timezone()
1783 }
1784
1785 fn volatile_level(&self) -> VolatileLevel {
1787 VolatileLevel::Always
1788 }
1789
1790 fn workbook_seed(&self) -> u64 {
1792 0xF0F0_D0D0_AAAA_5555
1793 }
1794
1795 fn recalc_epoch(&self) -> u64 {
1797 0
1798 }
1799
1800 fn used_rows_for_columns(
1805 &self,
1806 _sheet: &str,
1807 _start_col: u32,
1808 _end_col: u32,
1809 ) -> Option<(u32, u32)> {
1810 None
1811 }
1812
1813 fn used_cols_for_rows(
1816 &self,
1817 _sheet: &str,
1818 _start_row: u32,
1819 _end_row: u32,
1820 ) -> Option<(u32, u32)> {
1821 None
1822 }
1823
1824 fn sheet_bounds(&self, _sheet: &str) -> Option<(u32, u32)> {
1826 None
1827 }
1828
1829 fn data_snapshot_id(&self) -> u64 {
1831 0
1832 }
1833
1834 fn backend_caps(&self) -> BackendCaps {
1836 BackendCaps::default()
1837 }
1838
1839 fn date_system(&self) -> crate::engine::DateSystem {
1844 crate::engine::DateSystem::Excel1900
1845 }
1846
1847 fn build_lookup_index(
1850 &self,
1851 _view: &RangeView<'_>,
1852 _axis: LookupAxis,
1853 ) -> Option<std::sync::Arc<LookupIndex>> {
1854 None
1855 }
1856
1857 fn build_criteria_mask(
1860 &self,
1861 _view: &RangeView<'_>,
1862 _col_in_view: usize,
1863 _pred: &crate::args::CriteriaPredicate,
1864 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1865 None
1866 }
1867
1868 fn build_row_visibility_mask(
1871 &self,
1872 _view: &RangeView<'_>,
1873 _mode: VisibilityMaskMode,
1874 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1875 None
1876 }
1877}
1878
1879#[derive(Copy, Clone, Debug, Default)]
1881pub struct BackendCaps {
1882 pub streaming: bool,
1884 pub used_region: bool,
1886 pub write: bool,
1888 pub tables: bool,
1890 pub async_stream: bool,
1892}
1893
1894#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1897pub enum VolatileLevel {
1898 Always,
1900 OnRecalc,
1902 OnOpen,
1904}
1905
1906pub trait FunctionContext<'ctx> {
1908 fn locale(&self) -> crate::locale::Locale;
1909 fn timezone(&self) -> &crate::timezone::TimeZoneSpec;
1910 fn clock(&self) -> &dyn crate::timezone::ClockProvider;
1911 fn thread_pool(&self) -> Option<&std::sync::Arc<rayon::ThreadPool>>;
1912 fn cancellation_token(&self) -> Option<crate::engine::CancelToken>;
1918 fn chunk_hint(&self) -> Option<usize>;
1919
1920 fn current_sheet(&self) -> &str;
1922
1923 fn workbook_sheet_count(&self) -> Option<usize> {
1924 None
1925 }
1926
1927 fn sheet_index_by_name(&self, _sheet: &str) -> Option<usize> {
1928 None
1929 }
1930
1931 fn current_sheet_index(&self) -> Option<usize> {
1932 self.sheet_index_by_name(self.current_sheet())
1933 }
1934
1935 fn inspect_reference(
1936 &self,
1937 _reference: &ReferenceType,
1938 ) -> Result<Option<ReferenceInfo>, ExcelError> {
1939 Ok(None)
1940 }
1941
1942 fn formula_text_at_cell(&self, _cell: CellRef) -> Result<Option<String>, ExcelError> {
1943 Ok(None)
1944 }
1945
1946 fn volatile_level(&self) -> VolatileLevel;
1947 fn workbook_seed(&self) -> u64;
1948 fn recalc_epoch(&self) -> u64;
1949 fn current_cell(&self) -> Option<CellRef>;
1950
1951 fn resolve_range_view(
1953 &self,
1954 _reference: &ReferenceType,
1955 _current_sheet: &str,
1956 ) -> Result<RangeView<'ctx>, ExcelError>;
1957
1958 fn rng_for_current(&self, fn_salt: u64) -> rand::rngs::SmallRng {
1962 use crate::rng::{compose_seed, small_rng_from_lanes};
1963 let (sheet_id, row, col) = self
1964 .current_cell()
1965 .map(|c| (c.sheet_id as u32, c.coord.row(), c.coord.col()))
1966 .unwrap_or((0, 0, 0));
1967 let epoch = match self.volatile_level() {
1969 VolatileLevel::OnRecalc => self.recalc_epoch(),
1970 _ => 0,
1971 };
1972 let (l0, l1) = compose_seed(self.workbook_seed(), sheet_id, row, col, fn_salt, epoch);
1973 small_rng_from_lanes(l0, l1)
1974 }
1975
1976 fn date_system(&self) -> crate::engine::DateSystem {
1978 crate::engine::DateSystem::Excel1900
1979 }
1980
1981 fn get_lookup_index(
1984 &self,
1985 _view: &RangeView<'_>,
1986 _axis: LookupAxis,
1987 ) -> Option<std::sync::Arc<LookupIndex>> {
1988 None
1989 }
1990
1991 fn get_criteria_mask(
1994 &self,
1995 _view: &RangeView<'_>,
1996 _col_in_view: usize,
1997 _pred: &crate::args::CriteriaPredicate,
1998 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1999 None
2000 }
2001
2002 fn get_row_visibility_mask(
2004 &self,
2005 _view: &RangeView<'_>,
2006 _mode: VisibilityMaskMode,
2007 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2008 None
2009 }
2010}
2011
2012pub struct DefaultFunctionContext<'a> {
2014 pub base: &'a dyn EvaluationContext,
2015 pub current: Option<CellRef>,
2016 pub current_sheet: &'a str,
2017}
2018
2019impl<'a> DefaultFunctionContext<'a> {
2020 pub fn new(
2021 base: &'a dyn EvaluationContext,
2022 current: Option<CellRef>,
2023 current_sheet: &'a str,
2024 ) -> Self {
2025 Self {
2026 base,
2027 current,
2028 current_sheet,
2029 }
2030 }
2031
2032 pub fn new_with_sheet(
2033 base: &'a dyn EvaluationContext,
2034 current: Option<CellRef>,
2035 current_sheet: &'a str,
2036 ) -> Self {
2037 Self::new(base, current, current_sheet)
2038 }
2039}
2040
2041impl<'a> FunctionContext<'a> for DefaultFunctionContext<'a> {
2042 fn locale(&self) -> crate::locale::Locale {
2043 self.base.locale()
2044 }
2045
2046 fn current_sheet(&self) -> &str {
2047 self.current_sheet
2048 }
2049
2050 fn workbook_sheet_count(&self) -> Option<usize> {
2051 self.base.workbook_sheet_count()
2052 }
2053
2054 fn sheet_index_by_name(&self, sheet: &str) -> Option<usize> {
2055 self.base.sheet_index_by_name(sheet)
2056 }
2057
2058 fn current_sheet_index(&self) -> Option<usize> {
2059 self.base.current_sheet_index(self.current_sheet)
2060 }
2061
2062 fn inspect_reference(
2063 &self,
2064 reference: &ReferenceType,
2065 ) -> Result<Option<ReferenceInfo>, ExcelError> {
2066 self.base.inspect_reference(reference, self.current_sheet)
2067 }
2068
2069 fn formula_text_at_cell(&self, cell: CellRef) -> Result<Option<String>, ExcelError> {
2070 self.base.formula_text_at_cell(cell)
2071 }
2072
2073 fn timezone(&self) -> &crate::timezone::TimeZoneSpec {
2074 self.base.timezone()
2075 }
2076
2077 fn clock(&self) -> &dyn crate::timezone::ClockProvider {
2078 self.base.clock()
2079 }
2080 fn thread_pool(&self) -> Option<&std::sync::Arc<rayon::ThreadPool>> {
2081 self.base.thread_pool()
2082 }
2083 fn cancellation_token(&self) -> Option<crate::engine::CancelToken> {
2084 self.base.cancellation_token()
2085 }
2086 fn chunk_hint(&self) -> Option<usize> {
2087 self.base.chunk_hint()
2088 }
2089
2090 fn volatile_level(&self) -> VolatileLevel {
2091 self.base.volatile_level()
2092 }
2093 fn workbook_seed(&self) -> u64 {
2094 self.base.workbook_seed()
2095 }
2096 fn recalc_epoch(&self) -> u64 {
2097 self.base.recalc_epoch()
2098 }
2099 fn current_cell(&self) -> Option<CellRef> {
2100 self.current
2101 }
2102
2103 fn resolve_range_view(
2104 &self,
2105 reference: &ReferenceType,
2106 current_sheet: &str,
2107 ) -> Result<RangeView<'a>, ExcelError> {
2108 self.base.resolve_range_view(reference, current_sheet)
2109 }
2110
2111 fn date_system(&self) -> crate::engine::DateSystem {
2114 self.base.date_system()
2115 }
2116
2117 fn get_lookup_index(
2118 &self,
2119 view: &RangeView<'_>,
2120 axis: LookupAxis,
2121 ) -> Option<std::sync::Arc<LookupIndex>> {
2122 self.base.build_lookup_index(view, axis)
2123 }
2124
2125 fn get_criteria_mask(
2126 &self,
2127 view: &RangeView<'_>,
2128 col_in_view: usize,
2129 pred: &crate::args::CriteriaPredicate,
2130 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2131 self.base.build_criteria_mask(view, col_in_view, pred)
2132 }
2133
2134 fn get_row_visibility_mask(
2135 &self,
2136 view: &RangeView<'_>,
2137 mode: VisibilityMaskMode,
2138 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
2139 self.base.build_row_visibility_mask(view, mode)
2140 }
2141}