1use crate::engine::range_view::RangeView;
2pub use crate::function::Function;
3use crate::interpreter::Interpreter;
4use crate::reference::CellRef;
5use formualizer_common::{
6 LiteralValue,
7 error::{ExcelError, ExcelErrorKind},
8};
9use std::any::Any;
10use std::borrow::Cow;
11use std::fmt::Debug;
12use std::sync::Arc;
13
14use formualizer_parse::parser::{ASTNode, ASTNodeType, ReferenceType, TableSpecifier};
15
16pub trait Range: Debug + Send + Sync {
19 fn get(&self, row: usize, col: usize) -> Result<LiteralValue, ExcelError>;
20 fn dimensions(&self) -> (usize, usize);
21
22 fn is_sparse(&self) -> bool {
23 false
24 }
25
26 fn is_infinite(&self) -> bool {
28 false
29 }
30
31 fn materialise(&self) -> Cow<'_, [Vec<LiteralValue>]> {
32 Cow::Owned(
33 (0..self.dimensions().0)
34 .map(|r| {
35 (0..self.dimensions().1)
36 .map(|c| self.get(r, c).unwrap_or(LiteralValue::Empty))
37 .collect()
38 })
39 .collect(),
40 )
41 }
42
43 fn iter_cells<'a>(&'a self) -> Box<dyn Iterator<Item = LiteralValue> + 'a> {
44 let (rows, cols) = self.dimensions();
45 Box::new((0..rows).flat_map(move |r| (0..cols).map(move |c| self.get(r, c).unwrap())))
46 }
47 fn iter_rows<'a>(&'a self) -> Box<dyn Iterator<Item = Vec<LiteralValue>> + 'a> {
48 let (rows, cols) = self.dimensions();
49 Box::new((0..rows).map(move |r| (0..cols).map(|c| self.get(r, c).unwrap()).collect()))
50 }
51
52 fn as_any(&self) -> &dyn Any;
54}
55
56impl Range for Box<dyn Range> {
58 fn get(&self, r: usize, c: usize) -> Result<LiteralValue, ExcelError> {
59 (**self).get(r, c)
60 }
61 fn dimensions(&self) -> (usize, usize) {
62 (**self).dimensions()
63 }
64 fn is_sparse(&self) -> bool {
65 (**self).is_sparse()
66 }
67 fn materialise(&self) -> Cow<'_, [Vec<LiteralValue>]> {
68 (**self).materialise()
69 }
70 fn iter_cells<'a>(&'a self) -> Box<dyn Iterator<Item = LiteralValue> + 'a> {
71 (**self).iter_cells()
72 }
73 fn iter_rows<'a>(&'a self) -> Box<dyn Iterator<Item = Vec<LiteralValue>> + 'a> {
74 (**self).iter_rows()
75 }
76 fn as_any(&self) -> &dyn Any {
77 (**self).as_any()
78 }
79}
80
81pub type CowValue<'a> = Cow<'a, LiteralValue>;
84
85#[derive(Debug, Clone)]
86pub enum CalcValue<'a> {
87 Scalar(LiteralValue),
88 Range(RangeView<'a>),
89}
90
91impl<'a> CalcValue<'a> {
92 pub fn into_literal(self) -> LiteralValue {
93 match self {
94 CalcValue::Scalar(s) => s,
95 CalcValue::Range(rv) => {
96 let (rows, cols) = rv.dims();
97 if rows == 1 && cols == 1 {
98 rv.get_cell(0, 0)
99 } else {
100 let mut data = Vec::with_capacity(rows);
101 let _ = rv.for_each_row(&mut |row| {
104 data.push(row.to_vec());
105 Ok(())
106 });
107 LiteralValue::Array(data)
108 }
109 }
110 }
111 }
112
113 pub fn as_scalar(&self) -> Option<&LiteralValue> {
114 match self {
115 CalcValue::Scalar(s) => Some(s),
116 _ => None,
117 }
118 }
119
120 pub fn as_range(&self) -> Option<&RangeView<'a>> {
121 match self {
122 CalcValue::Range(r) => Some(r),
123 _ => None,
124 }
125 }
126
127 pub fn into_owned(self) -> LiteralValue {
128 self.into_literal()
129 }
130}
131
132impl From<CalcValue<'_>> for LiteralValue {
133 fn from(val: CalcValue<'_>) -> Self {
134 val.into_literal()
135 }
136}
137
138impl<'a> PartialEq<LiteralValue> for CalcValue<'a> {
139 fn eq(&self, other: &LiteralValue) -> bool {
140 match self {
141 CalcValue::Scalar(s) => s == other,
142 CalcValue::Range(rv) => match other {
143 LiteralValue::Array(arr) => {
144 let (rows, cols) = rv.dims();
145 if arr.len() != rows {
146 return false;
147 }
148 for (r, row) in arr.iter().enumerate() {
149 if row.len() != cols {
150 return false;
151 }
152 for (c, cell) in row.iter().enumerate() {
153 if &rv.get_cell(r, c) != cell {
154 return false;
155 }
156 }
157 }
158 true
159 }
160 _ => {
161 let (rows, cols) = rv.dims();
162 rows == 1 && cols == 1 && &rv.get_cell(0, 0) == other
163 }
164 },
165 }
166 }
167}
168
169impl<'a> PartialEq<CalcValue<'a>> for LiteralValue {
170 fn eq(&self, other: &CalcValue<'a>) -> bool {
171 other == self
172 }
173}
174
175pub enum EvaluatedArg<'a> {
176 LiteralValue(CowValue<'a>),
177 Range(Box<dyn Range>),
178}
179
180enum ArgumentExpr<'a> {
181 Ast(&'a ASTNode),
182 Arena {
183 id: crate::engine::arena::AstNodeId,
184 data_store: &'a crate::engine::arena::DataStore,
185 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
186 },
187}
188
189pub struct ArgumentHandle<'a, 'b> {
190 expr: ArgumentExpr<'a>,
191 interp: &'a Interpreter<'b>,
192 cached_ast: std::cell::OnceCell<ASTNode>,
193 cached_ref: std::cell::OnceCell<ReferenceType>,
194}
195
196impl<'a, 'b> ArgumentHandle<'a, 'b> {
197 pub(crate) fn new(node: &'a ASTNode, interp: &'a Interpreter<'b>) -> Self {
198 Self {
199 expr: ArgumentExpr::Ast(node),
200 interp,
201 cached_ast: std::cell::OnceCell::new(),
202 cached_ref: std::cell::OnceCell::new(),
203 }
204 }
205
206 pub(crate) fn new_arena(
207 id: crate::engine::arena::AstNodeId,
208 interp: &'a Interpreter<'b>,
209 data_store: &'a crate::engine::arena::DataStore,
210 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
211 ) -> Self {
212 Self {
213 expr: ArgumentExpr::Arena {
214 id,
215 data_store,
216 sheet_registry,
217 },
218 interp,
219 cached_ast: std::cell::OnceCell::new(),
220 cached_ref: std::cell::OnceCell::new(),
221 }
222 }
223
224 pub fn value(&self) -> Result<crate::traits::CalcValue<'b>, ExcelError> {
225 match &self.expr {
226 ArgumentExpr::Ast(node) => {
227 if let ASTNodeType::Literal(ref v) = node.node_type {
228 return Ok(crate::traits::CalcValue::Scalar(v.clone()));
229 }
230 self.interp.evaluate_ast(node)
231 }
232 ArgumentExpr::Arena {
233 id,
234 data_store,
235 sheet_registry,
236 } => self
237 .interp
238 .evaluate_arena_ast(*id, data_store, sheet_registry),
239 }
240 }
241
242 pub fn inline_array_literal(&self) -> Result<Option<Vec<Vec<LiteralValue>>>, ExcelError> {
243 match &self.expr {
244 ArgumentExpr::Ast(node) => match &node.node_type {
245 ASTNodeType::Literal(LiteralValue::Array(arr)) => Ok(Some(arr.clone())),
246 _ => Ok(None),
247 },
248 ArgumentExpr::Arena {
249 id,
250 data_store,
251 sheet_registry,
252 } => {
253 let node = data_store.get_node(*id).ok_or_else(|| {
254 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
255 })?;
256 match node {
257 crate::engine::arena::AstNodeData::Literal(vref) => {
258 match data_store.retrieve_value(*vref) {
259 LiteralValue::Array(arr) => Ok(Some(arr)),
260 _ => Ok(None),
261 }
262 }
263 _ => {
264 let _ = sheet_registry;
267 Ok(None)
268 }
269 }
270 }
271 }
272 }
273
274 fn reference_for_eval(&self) -> Result<ReferenceType, ExcelError> {
275 match &self.expr {
276 ArgumentExpr::Ast(node) => match &node.node_type {
277 ASTNodeType::Reference { reference, .. } => Ok(reference.clone()),
278 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
279 self.interp.evaluate_ast_as_reference(node)
280 }
281 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
282 .with_message("Expected a reference (by-ref argument)")),
283 },
284 ArgumentExpr::Arena {
285 id,
286 data_store,
287 sheet_registry,
288 } => {
289 let node = data_store.get_node(*id).ok_or_else(|| {
290 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
291 })?;
292 match node {
293 crate::engine::arena::AstNodeData::Reference { ref_type, .. } => Ok(
294 data_store.reconstruct_reference_type_for_eval(ref_type, sheet_registry)
295 ),
296 crate::engine::arena::AstNodeData::Function { .. }
297 | crate::engine::arena::AstNodeData::BinaryOp { .. } => self
298 .interp
299 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry),
300 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
301 .with_message("Expected a reference (by-ref argument)")),
302 }
303 }
304 }
305 }
306
307 pub fn range(&self) -> Result<Box<dyn Range>, ExcelError> {
308 match &self.expr {
309 ArgumentExpr::Ast(node) => match &node.node_type {
310 ASTNodeType::Reference { reference, .. } => {
311 let view = self
313 .interp
314 .context
315 .resolve_range_view(reference, self.interp.current_sheet())?;
316 let (rows, cols) = view.dims();
317 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
318 view.for_each_row(&mut |row| {
319 let row_data: Vec<LiteralValue> = (0..cols)
320 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
321 .collect();
322 out.push(row_data);
323 Ok(())
324 })?;
325 Ok(Box::new(InMemoryRange::new(out)))
326 }
327 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
328 let reference = self.reference_for_eval()?;
329 let view = self
330 .interp
331 .context
332 .resolve_range_view(&reference, self.interp.current_sheet())?;
333 let (rows, cols) = view.dims();
334 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
335 view.for_each_row(&mut |row| {
336 let row_data: Vec<LiteralValue> = (0..cols)
337 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
338 .collect();
339 out.push(row_data);
340 Ok(())
341 })?;
342 Ok(Box::new(InMemoryRange::new(out)))
343 }
344 ASTNodeType::Array(rows) => {
345 let mut materialized = Vec::new();
346 for row in rows {
347 let mut materialized_row = Vec::new();
348 for cell in row {
349 materialized_row.push(self.interp.evaluate_ast(cell)?.into_literal());
350 }
351 materialized.push(materialized_row);
352 }
353 Ok(Box::new(InMemoryRange::new(materialized)))
354 }
355 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
356 .with_message(format!("Expected a range, got {:?}", node.node_type))),
357 },
358 ArgumentExpr::Arena { id, data_store, .. } => {
359 let node = data_store.get_node(*id).ok_or_else(|| {
360 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
361 })?;
362
363 match node {
364 crate::engine::arena::AstNodeData::Reference { .. }
365 | crate::engine::arena::AstNodeData::Function { .. }
366 | crate::engine::arena::AstNodeData::BinaryOp { .. } => {
367 let reference = self.reference_for_eval()?;
368 let view = self
369 .interp
370 .context
371 .resolve_range_view(&reference, self.interp.current_sheet())?;
372 let (rows, cols) = view.dims();
373 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
374 view.for_each_row(&mut |row| {
375 let row_data: Vec<LiteralValue> = (0..cols)
376 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
377 .collect();
378 out.push(row_data);
379 Ok(())
380 })?;
381 Ok(Box::new(InMemoryRange::new(out)))
382 }
383 crate::engine::arena::AstNodeData::Array { .. } => {
384 let (rows, cols, elements) =
385 data_store.get_array_elems(*id).ok_or_else(|| {
386 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
387 })?;
388 let rows_usize = rows as usize;
389 let cols_usize = cols as usize;
390 let mut materialized: Vec<Vec<LiteralValue>> =
391 Vec::with_capacity(rows_usize);
392 for r in 0..rows_usize {
393 let mut row = Vec::with_capacity(cols_usize);
394 for c in 0..cols_usize {
395 let idx = r * cols_usize + c;
396 let elem_id = elements.get(idx).copied().ok_or_else(|| {
397 ExcelError::new(ExcelErrorKind::Value)
398 .with_message("Invalid array")
399 })?;
400 let v = self.interp.evaluate_arena_ast(
401 elem_id,
402 data_store,
403 self.sheet_registry(),
404 )?;
405 row.push(v.into_literal());
406 }
407 materialized.push(row);
408 }
409 Ok(Box::new(InMemoryRange::new(materialized)))
410 }
411 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
412 .with_message("Argument cannot be interpreted as a range.")),
413 }
414 }
415 }
416 }
417
418 fn sheet_registry(&self) -> &crate::engine::sheet_registry::SheetRegistry {
419 match &self.expr {
420 ArgumentExpr::Ast(_) => {
421 unreachable!("sheet_registry only used for arena ArgumentHandle")
423 }
424 ArgumentExpr::Arena { sheet_registry, .. } => sheet_registry,
425 }
426 }
427
428 pub fn range_view(&self) -> Result<RangeView<'b>, ExcelError> {
430 match &self.expr {
431 ArgumentExpr::Ast(node) => match &node.node_type {
432 ASTNodeType::Reference { reference, .. } => self
433 .interp
434 .context
435 .resolve_range_view(reference, self.interp.current_sheet())
436 .map(|v| v.with_cancel_token(self.interp.context.cancellation_token())),
437 ASTNodeType::Literal(formualizer_common::LiteralValue::Array(arr)) => Ok(
439 RangeView::from_owned_rows(arr.clone(), self.interp.context.date_system())
440 .with_cancel_token(self.interp.context.cancellation_token()),
441 ),
442 ASTNodeType::Array(rows) => {
443 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows.len());
444 for r in rows {
445 let mut row_vals = Vec::with_capacity(r.len());
446 for cell in r {
447 row_vals.push(self.interp.evaluate_ast(cell)?.into_literal());
448 }
449 out.push(row_vals);
450 }
451 Ok(
452 RangeView::from_owned_rows(out, self.interp.context.date_system())
453 .with_cancel_token(self.interp.context.cancellation_token()),
454 )
455 }
456 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
457 let reference = self.reference_for_eval()?;
458 self.interp
459 .context
460 .resolve_range_view(&reference, self.interp.current_sheet())
461 .map(|v| v.with_cancel_token(self.interp.context.cancellation_token()))
462 }
463 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
464 .with_message("Argument cannot be interpreted as a range.")),
465 },
466 ArgumentExpr::Arena {
467 id,
468 data_store,
469 sheet_registry,
470 } => {
471 let node = data_store.get_node(*id).ok_or_else(|| {
472 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
473 })?;
474
475 match node {
476 crate::engine::arena::AstNodeData::Reference { .. }
477 | crate::engine::arena::AstNodeData::Function { .. }
478 | crate::engine::arena::AstNodeData::BinaryOp { .. } => {
479 let reference = self.reference_for_eval()?;
480 self.interp
481 .context
482 .resolve_range_view(&reference, self.interp.current_sheet())
483 .map(|v| v.with_cancel_token(self.interp.context.cancellation_token()))
484 }
485 crate::engine::arena::AstNodeData::Literal(vref) => {
486 match data_store.retrieve_value(*vref) {
487 LiteralValue::Array(arr) => Ok(RangeView::from_owned_rows(
488 arr,
489 self.interp.context.date_system(),
490 )
491 .with_cancel_token(self.interp.context.cancellation_token())),
492 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
493 .with_message("Argument cannot be interpreted as a range.")),
494 }
495 }
496 crate::engine::arena::AstNodeData::Array { .. } => {
497 let (rows, cols, elements) =
498 data_store.get_array_elems(*id).ok_or_else(|| {
499 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
500 })?;
501
502 let rows_usize = rows as usize;
503 let cols_usize = cols as usize;
504 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows_usize);
505 for r in 0..rows_usize {
506 let mut row = Vec::with_capacity(cols_usize);
507 for c in 0..cols_usize {
508 let idx = r * cols_usize + c;
509 let elem_id = elements.get(idx).copied().ok_or_else(|| {
510 ExcelError::new(ExcelErrorKind::Value)
511 .with_message("Invalid array")
512 })?;
513 let v = self.interp.evaluate_arena_ast(
514 elem_id,
515 data_store,
516 sheet_registry,
517 )?;
518 row.push(v.into_literal());
519 }
520 out.push(row);
521 }
522 Ok(
523 RangeView::from_owned_rows(out, self.interp.context.date_system())
524 .with_cancel_token(self.interp.context.cancellation_token()),
525 )
526 }
527 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
528 .with_message("Argument cannot be interpreted as a range.")),
529 }
530 }
531 }
532 }
533
534 pub fn value_or_range(&self) -> Result<EvaluatedArg<'_>, ExcelError> {
535 self.range().map(EvaluatedArg::Range).or_else(|_| {
536 self.value()
537 .map(|cv| EvaluatedArg::LiteralValue(Cow::Owned(cv.into_literal())))
538 })
539 }
540
541 pub fn lazy_values_owned(
546 &'a self,
547 ) -> Result<Box<dyn Iterator<Item = LiteralValue> + 'a>, ExcelError> {
548 match &self.expr {
549 ArgumentExpr::Ast(node) => match &node.node_type {
550 ASTNodeType::Reference { .. } => {
551 let view = self.range_view()?;
552 let mut values: Vec<LiteralValue> = Vec::new();
553 view.for_each_cell(&mut |v| {
554 values.push(v.clone());
555 Ok(())
556 })?;
557 Ok(Box::new(values.into_iter()))
558 }
559 ASTNodeType::Array(rows) => {
560 struct ArrayEvalIter<'a, 'b> {
561 rows: &'a [Vec<ASTNode>],
562 r: usize,
563 c: usize,
564 interp: &'a Interpreter<'b>,
565 }
566 impl<'a, 'b> Iterator for ArrayEvalIter<'a, 'b> {
567 type Item = LiteralValue;
568 fn next(&mut self) -> Option<Self::Item> {
569 if self.rows.is_empty() {
570 return None;
571 }
572 let rows = self.rows;
573 let mut r = self.r;
574 let mut c = self.c;
575 if r >= rows.len() {
576 return None;
577 }
578 let node = &rows[r][c];
579 c += 1;
581 if c >= rows[r].len() {
582 r += 1;
583 c = 0;
584 }
585 self.r = r;
586 self.c = c;
587 match self.interp.evaluate_ast(node) {
588 Ok(cv) => Some(cv.into_literal()),
589 Err(e) => Some(LiteralValue::Error(e)),
590 }
591 }
592 }
593 let it = ArrayEvalIter {
594 rows,
595 r: 0,
596 c: 0,
597 interp: self.interp,
598 };
599 Ok(Box::new(it))
600 }
601 _ => {
602 let v = self.value()?.into_literal();
604 Ok(Box::new(std::iter::once(v)))
605 }
606 },
607 ArgumentExpr::Arena {
608 id,
609 data_store,
610 sheet_registry,
611 } => {
612 let node = data_store.get_node(*id).ok_or_else(|| {
613 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
614 })?;
615
616 match node {
617 crate::engine::arena::AstNodeData::Reference { .. } => {
618 let view = self.range_view()?;
619 let mut values: Vec<LiteralValue> = Vec::new();
620 view.for_each_cell(&mut |v| {
621 values.push(v.clone());
622 Ok(())
623 })?;
624 Ok(Box::new(values.into_iter()))
625 }
626 crate::engine::arena::AstNodeData::Array { .. } => {
627 let (rows, cols, elements) =
628 data_store.get_array_elems(*id).ok_or_else(|| {
629 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
630 })?;
631
632 struct ArenaArrayEvalIter<'a, 'b> {
633 elements: &'a [crate::engine::arena::AstNodeId],
634 idx: usize,
635 interp: &'a Interpreter<'b>,
636 data_store: &'a crate::engine::arena::DataStore,
637 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
638 }
639
640 impl<'a, 'b> Iterator for ArenaArrayEvalIter<'a, 'b> {
641 type Item = LiteralValue;
642
643 fn next(&mut self) -> Option<Self::Item> {
644 let id = self.elements.get(self.idx).copied()?;
645 self.idx += 1;
646 match self.interp.evaluate_arena_ast(
647 id,
648 self.data_store,
649 self.sheet_registry,
650 ) {
651 Ok(cv) => Some(cv.into_literal()),
652 Err(e) => Some(LiteralValue::Error(e)),
653 }
654 }
655 }
656
657 let _ = (rows, cols);
658 let it = ArenaArrayEvalIter {
659 elements,
660 idx: 0,
661 interp: self.interp,
662 data_store,
663 sheet_registry,
664 };
665 Ok(Box::new(it))
666 }
667 _ => {
668 let v = self
669 .interp
670 .evaluate_arena_ast(*id, data_store, sheet_registry)?;
671 Ok(Box::new(std::iter::once(v.into_literal())))
672 }
673 }
674 }
675 }
676 }
677
678 pub fn ast(&self) -> &ASTNode {
679 match &self.expr {
680 ArgumentExpr::Ast(node) => node,
681 ArgumentExpr::Arena {
682 id,
683 data_store,
684 sheet_registry,
685 } => self.cached_ast.get_or_init(|| {
686 data_store
687 .retrieve_ast(*id, sheet_registry)
688 .unwrap_or_else(|| ASTNode {
689 node_type: ASTNodeType::Literal(LiteralValue::Error(
690 ExcelError::new(ExcelErrorKind::Value)
691 .with_message("Missing formula AST"),
692 )),
693 source_token: None,
694 contains_volatile: false,
695 })
696 }),
697 }
698 }
699
700 pub fn as_reference(&self) -> Result<&ReferenceType, ExcelError> {
703 match &self.expr {
704 ArgumentExpr::Ast(node) => match &node.node_type {
705 ASTNodeType::Reference { reference, .. } => Ok(reference),
706 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
707 .with_message("Expected a reference (by-ref argument)")),
708 },
709 ArgumentExpr::Arena { .. } => {
710 let reference = self.reference_for_eval()?;
711 Ok(self.cached_ref.get_or_init(|| reference))
712 }
713 }
714 }
715
716 pub fn as_reference_or_eval(&self) -> Result<ReferenceType, ExcelError> {
719 match &self.expr {
720 ArgumentExpr::Ast(node) => match &node.node_type {
721 ASTNodeType::Reference { reference, .. } => Ok(reference.clone()),
722 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
723 self.interp.evaluate_ast_as_reference(node)
724 }
725 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
726 .with_message("Argument is not a reference")),
727 },
728 ArgumentExpr::Arena {
729 id,
730 data_store,
731 sheet_registry,
732 } => {
733 let node = data_store.get_node(*id).ok_or_else(|| {
734 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
735 })?;
736
737 match node {
738 crate::engine::arena::AstNodeData::Reference { .. } => {
739 self.reference_for_eval()
740 }
741 crate::engine::arena::AstNodeData::Function { .. }
742 | crate::engine::arena::AstNodeData::BinaryOp { .. } => self
743 .interp
744 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry),
745 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
746 .with_message("Argument is not a reference")),
747 }
748 }
749 }
750 }
751
752 pub fn matches_kind(&self, k: formualizer_common::ArgKind) -> Result<bool, ExcelError> {
754 Ok(match k {
755 formualizer_common::ArgKind::Any => true,
756 formualizer_common::ArgKind::Range => self.range().is_ok(),
757 formualizer_common::ArgKind::Number => matches!(
758 self.value()?.into_literal(),
759 LiteralValue::Number(_) | LiteralValue::Int(_)
760 ),
761 formualizer_common::ArgKind::Text => {
762 matches!(self.value()?.into_literal(), LiteralValue::Text(_))
763 }
764 formualizer_common::ArgKind::Logical => {
765 matches!(self.value()?.into_literal(), LiteralValue::Boolean(_))
766 }
767 })
768 }
769}
770
771#[derive(Debug, Clone)]
773pub struct InMemoryRange {
774 data: Vec<Vec<LiteralValue>>,
775}
776impl InMemoryRange {
777 pub fn new(d: Vec<Vec<LiteralValue>>) -> Self {
778 Self { data: d }
779 }
780}
781impl Range for InMemoryRange {
782 fn get(&self, r: usize, c: usize) -> Result<LiteralValue, ExcelError> {
783 Ok(self
784 .data
785 .get(r)
786 .and_then(|row| row.get(c))
787 .cloned()
788 .unwrap_or(LiteralValue::Empty))
789 }
790 fn dimensions(&self) -> (usize, usize) {
791 (self.data.len(), self.data.first().map_or(0, |r| r.len()))
792 }
793 fn as_any(&self) -> &dyn Any {
794 self
795 }
796}
797
798pub trait Table: Debug + Send + Sync {
801 fn get_cell(&self, row: usize, column: &str) -> Result<LiteralValue, ExcelError>;
802 fn get_column(&self, column: &str) -> Result<Box<dyn Range>, ExcelError>;
803 fn columns(&self) -> Vec<String> {
805 vec![]
806 }
807 fn data_height(&self) -> usize {
809 0
810 }
811 fn has_headers(&self) -> bool {
813 false
814 }
815 fn has_totals(&self) -> bool {
817 false
818 }
819 fn headers_row(&self) -> Option<Box<dyn Range>> {
821 None
822 }
823 fn totals_row(&self) -> Option<Box<dyn Range>> {
825 None
826 }
827 fn data_body(&self) -> Option<Box<dyn Range>> {
829 None
830 }
831 fn clone_box(&self) -> Box<dyn Table>;
832}
833impl Table for Box<dyn Table> {
834 fn get_cell(&self, r: usize, c: &str) -> Result<LiteralValue, ExcelError> {
835 (**self).get_cell(r, c)
836 }
837 fn get_column(&self, c: &str) -> Result<Box<dyn Range>, ExcelError> {
838 (**self).get_column(c)
839 }
840 fn columns(&self) -> Vec<String> {
841 (**self).columns()
842 }
843 fn data_height(&self) -> usize {
844 (**self).data_height()
845 }
846 fn has_headers(&self) -> bool {
847 (**self).has_headers()
848 }
849 fn has_totals(&self) -> bool {
850 (**self).has_totals()
851 }
852 fn headers_row(&self) -> Option<Box<dyn Range>> {
853 (**self).headers_row()
854 }
855 fn totals_row(&self) -> Option<Box<dyn Range>> {
856 (**self).totals_row()
857 }
858 fn data_body(&self) -> Option<Box<dyn Range>> {
859 (**self).data_body()
860 }
861 fn clone_box(&self) -> Box<dyn Table> {
862 (**self).clone_box()
863 }
864}
865
866pub trait ReferenceResolver: Send + Sync {
869 fn resolve_cell_reference(
870 &self,
871 sheet: Option<&str>,
872 row: u32,
873 col: u32,
874 ) -> Result<LiteralValue, ExcelError>;
875}
876pub trait RangeResolver: Send + Sync {
877 fn resolve_range_reference(
878 &self,
879 sheet: Option<&str>,
880 sr: Option<u32>,
881 sc: Option<u32>,
882 er: Option<u32>,
883 ec: Option<u32>,
884 ) -> Result<Box<dyn Range>, ExcelError>;
885}
886pub trait NamedRangeResolver: Send + Sync {
887 fn resolve_named_range_reference(
888 &self,
889 name: &str,
890 ) -> Result<Vec<Vec<LiteralValue>>, ExcelError>;
891}
892pub trait TableResolver: Send + Sync {
893 fn resolve_table_reference(
894 &self,
895 tref: &formualizer_parse::parser::TableReference,
896 ) -> Result<Box<dyn Table>, ExcelError>;
897}
898
899pub trait SourceResolver: Send + Sync {
900 fn source_scalar_version(&self, _name: &str) -> Option<u64> {
901 None
902 }
903
904 fn resolve_source_scalar(&self, name: &str) -> Result<LiteralValue, ExcelError> {
905 Err(ExcelError::new(ExcelErrorKind::NImpl)
906 .with_message(format!("Source scalar not supported: {name}")))
907 }
908
909 fn source_table_version(&self, _name: &str) -> Option<u64> {
910 None
911 }
912
913 fn resolve_source_table(&self, name: &str) -> Result<Box<dyn Table>, ExcelError> {
914 Err(ExcelError::new(ExcelErrorKind::NImpl)
915 .with_message(format!("Source table not supported: {name}")))
916 }
917}
918
919pub trait Resolver: ReferenceResolver + RangeResolver + NamedRangeResolver + TableResolver {
920 fn resolve_range_like(&self, r: &ReferenceType) -> Result<Box<dyn Range>, ExcelError> {
921 match r {
922 ReferenceType::Range {
923 sheet,
924 start_row,
925 start_col,
926 end_row,
927 end_col,
928 ..
929 } => self.resolve_range_reference(
930 sheet.as_deref(),
931 *start_row,
932 *start_col,
933 *end_row,
934 *end_col,
935 ),
936 ReferenceType::External(_) => Err(ExcelError::new(ExcelErrorKind::NImpl)
937 .with_message("External references are not supported by Resolver".to_string())),
938 ReferenceType::Table(tref) => {
939 let t = self.resolve_table_reference(tref)?;
940 match &tref.specifier {
941 Some(TableSpecifier::Column(c)) => t.get_column(c),
942 Some(TableSpecifier::ColumnRange(start, end)) => {
943 let cols = t.columns();
945 let start_idx = cols.iter().position(|n| n.eq_ignore_ascii_case(start));
946 let end_idx = cols.iter().position(|n| n.eq_ignore_ascii_case(end));
947 if let (Some(mut si), Some(mut ei)) = (start_idx, end_idx) {
948 if si > ei {
949 std::mem::swap(&mut si, &mut ei);
950 }
951 let h = t.data_height();
953 let w = ei - si + 1;
954 let mut rows = vec![vec![LiteralValue::Empty; w]; h];
955 for (offset, ci) in (si..=ei).enumerate() {
956 let cname = &cols[ci];
957 let col_range = t.get_column(cname)?;
958 let (rh, _) = col_range.dimensions();
959 for (r, row) in rows.iter_mut().enumerate().take(h.min(rh)) {
960 row[offset] = col_range.get(r, 0)?;
961 }
962 }
963 Ok(Box::new(InMemoryRange::new(rows)))
964 } else {
965 Err(ExcelError::new(ExcelErrorKind::Ref).with_message(
966 "Column range refers to unknown column(s)".to_string(),
967 ))
968 }
969 }
970 Some(TableSpecifier::SpecialItem(
971 formualizer_parse::parser::SpecialItem::Headers,
972 )) => {
973 if let Some(h) = t.headers_row() {
974 Ok(h)
975 } else {
976 Ok(Box::new(InMemoryRange::new(vec![])))
977 }
978 }
979 Some(TableSpecifier::SpecialItem(
980 formualizer_parse::parser::SpecialItem::Totals,
981 )) => {
982 if let Some(tr) = t.totals_row() {
983 Ok(tr)
984 } else {
985 Ok(Box::new(InMemoryRange::new(vec![])))
986 }
987 }
988 Some(TableSpecifier::SpecialItem(
989 formualizer_parse::parser::SpecialItem::Data,
990 )) => {
991 if let Some(body) = t.data_body() {
992 Ok(body)
993 } else {
994 Ok(Box::new(InMemoryRange::new(vec![])))
995 }
996 }
997 Some(TableSpecifier::SpecialItem(
998 formualizer_parse::parser::SpecialItem::All,
999 )) => {
1000 let mut out: Vec<Vec<LiteralValue>> = Vec::new();
1002 if let Some(h) = t.headers_row() {
1003 out.extend(h.iter_rows());
1004 }
1005 if let Some(body) = t.data_body() {
1006 out.extend(body.iter_rows());
1007 }
1008 if let Some(tr) = t.totals_row() {
1009 out.extend(tr.iter_rows());
1010 }
1011 Ok(Box::new(InMemoryRange::new(out)))
1012 }
1013 Some(TableSpecifier::SpecialItem(
1014 formualizer_parse::parser::SpecialItem::ThisRow,
1015 )) => Err(ExcelError::new(ExcelErrorKind::NImpl).with_message(
1016 "@ (This Row) requires table-aware context; not yet supported".to_string(),
1017 )),
1018 Some(TableSpecifier::All) => {
1019 let mut out: Vec<Vec<LiteralValue>> = Vec::new();
1021 if let Some(h) = t.headers_row() {
1022 out.extend(h.iter_rows());
1023 }
1024 if let Some(body) = t.data_body() {
1025 out.extend(body.iter_rows());
1026 }
1027 if let Some(tr) = t.totals_row() {
1028 out.extend(tr.iter_rows());
1029 }
1030 Ok(Box::new(InMemoryRange::new(out)))
1031 }
1032 Some(TableSpecifier::Data) => {
1033 if let Some(body) = t.data_body() {
1034 Ok(body)
1035 } else {
1036 Ok(Box::new(InMemoryRange::new(vec![])))
1037 }
1038 }
1039 Some(TableSpecifier::Combination(_)) => Err(ExcelError::new(
1041 ExcelErrorKind::NImpl,
1042 )
1043 .with_message("Complex structured references not yet supported".to_string())),
1044 Some(TableSpecifier::Row(_)) => Err(ExcelError::new(ExcelErrorKind::NImpl)
1045 .with_message("Row selectors (@/index) not yet supported".to_string())),
1046 Some(TableSpecifier::Headers) | Some(TableSpecifier::Totals) => {
1047 Err(ExcelError::new(ExcelErrorKind::NImpl).with_message(
1048 "Legacy Headers/Totals variants not used; use SpecialItem".to_string(),
1049 ))
1050 }
1051 None => Err(ExcelError::new(ExcelErrorKind::Ref).with_message(
1052 "Table reference without specifier is unsupported".to_string(),
1053 )),
1054 }
1055 }
1056 ReferenceType::NamedRange(n) => {
1057 let v = self.resolve_named_range_reference(n)?;
1058 Ok(Box::new(InMemoryRange::new(v)))
1059 }
1060 ReferenceType::Cell {
1061 sheet, row, col, ..
1062 } => {
1063 let v = self.resolve_cell_reference(sheet.as_deref(), *row, *col)?;
1064 Ok(Box::new(InMemoryRange::new(vec![vec![v]])))
1065 }
1066 }
1067 }
1068}
1069
1070pub trait FunctionProvider: Send + Sync {
1073 fn get_function(&self, ns: &str, name: &str) -> Option<Arc<dyn Function>>;
1074}
1075
1076pub trait EvaluationContext: Resolver + FunctionProvider + SourceResolver {
1077 fn thread_pool(&self) -> Option<&Arc<rayon::ThreadPool>> {
1080 None
1081 }
1082
1083 fn cancellation_token(&self) -> Option<Arc<std::sync::atomic::AtomicBool>> {
1085 None
1086 }
1087
1088 fn chunk_hint(&self) -> Option<usize> {
1090 None
1091 }
1092
1093 fn resolve_range_view<'c>(
1096 &'c self,
1097 _reference: &ReferenceType,
1098 _current_sheet: &str,
1099 ) -> Result<RangeView<'c>, ExcelError> {
1100 Err(ExcelError::new(ExcelErrorKind::NImpl))
1101 }
1102
1103 fn locale(&self) -> crate::locale::Locale {
1105 crate::locale::Locale::invariant()
1106 }
1107
1108 fn timezone(&self) -> &crate::timezone::TimeZoneSpec {
1112 static DEFAULT_TZ: std::sync::OnceLock<crate::timezone::TimeZoneSpec> =
1114 std::sync::OnceLock::new();
1115 DEFAULT_TZ.get_or_init(crate::timezone::TimeZoneSpec::default)
1116 }
1117
1118 fn volatile_level(&self) -> VolatileLevel {
1120 VolatileLevel::Always
1121 }
1122
1123 fn workbook_seed(&self) -> u64 {
1125 0xF0F0_D0D0_AAAA_5555
1126 }
1127
1128 fn recalc_epoch(&self) -> u64 {
1130 0
1131 }
1132
1133 fn used_rows_for_columns(
1138 &self,
1139 _sheet: &str,
1140 _start_col: u32,
1141 _end_col: u32,
1142 ) -> Option<(u32, u32)> {
1143 None
1144 }
1145
1146 fn used_cols_for_rows(
1149 &self,
1150 _sheet: &str,
1151 _start_row: u32,
1152 _end_row: u32,
1153 ) -> Option<(u32, u32)> {
1154 None
1155 }
1156
1157 fn sheet_bounds(&self, _sheet: &str) -> Option<(u32, u32)> {
1159 None
1160 }
1161
1162 fn data_snapshot_id(&self) -> u64 {
1164 0
1165 }
1166
1167 fn backend_caps(&self) -> BackendCaps {
1169 BackendCaps::default()
1170 }
1171
1172 fn date_system(&self) -> crate::engine::DateSystem {
1177 crate::engine::DateSystem::Excel1900
1178 }
1179
1180 fn build_criteria_mask(
1183 &self,
1184 _view: &RangeView<'_>,
1185 _col_in_view: usize,
1186 _pred: &crate::args::CriteriaPredicate,
1187 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1188 None
1189 }
1190}
1191
1192#[derive(Copy, Clone, Debug, Default)]
1194pub struct BackendCaps {
1195 pub streaming: bool,
1197 pub used_region: bool,
1199 pub write: bool,
1201 pub tables: bool,
1203 pub async_stream: bool,
1205}
1206
1207#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1210pub enum VolatileLevel {
1211 Always,
1213 OnRecalc,
1215 OnOpen,
1217}
1218
1219pub trait FunctionContext<'ctx> {
1221 fn locale(&self) -> crate::locale::Locale;
1222 fn timezone(&self) -> &crate::timezone::TimeZoneSpec;
1223 fn thread_pool(&self) -> Option<&std::sync::Arc<rayon::ThreadPool>>;
1224 fn cancellation_token(&self) -> Option<Arc<std::sync::atomic::AtomicBool>>;
1225 fn chunk_hint(&self) -> Option<usize>;
1226
1227 fn current_sheet(&self) -> &str;
1229
1230 fn volatile_level(&self) -> VolatileLevel;
1231 fn workbook_seed(&self) -> u64;
1232 fn recalc_epoch(&self) -> u64;
1233 fn current_cell(&self) -> Option<CellRef>;
1234
1235 fn resolve_range_view(
1237 &self,
1238 _reference: &ReferenceType,
1239 _current_sheet: &str,
1240 ) -> Result<RangeView<'ctx>, ExcelError>;
1241
1242 fn rng_for_current(&self, fn_salt: u64) -> rand::rngs::SmallRng {
1246 use crate::rng::{compose_seed, small_rng_from_lanes};
1247 let (sheet_id, row, col) = self
1248 .current_cell()
1249 .map(|c| (c.sheet_id as u32, c.coord.row(), c.coord.col()))
1250 .unwrap_or((0, 0, 0));
1251 let epoch = match self.volatile_level() {
1253 VolatileLevel::OnRecalc => self.recalc_epoch(),
1254 _ => 0,
1255 };
1256 let (l0, l1) = compose_seed(self.workbook_seed(), sheet_id, row, col, fn_salt, epoch);
1257 small_rng_from_lanes(l0, l1)
1258 }
1259
1260 fn date_system(&self) -> crate::engine::DateSystem {
1262 crate::engine::DateSystem::Excel1900
1263 }
1264
1265 fn get_criteria_mask(
1268 &self,
1269 _view: &RangeView<'_>,
1270 _col_in_view: usize,
1271 _pred: &crate::args::CriteriaPredicate,
1272 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1273 None
1274 }
1275}
1276
1277pub struct DefaultFunctionContext<'a> {
1279 pub base: &'a dyn EvaluationContext,
1280 pub current: Option<CellRef>,
1281 pub current_sheet: &'a str,
1282}
1283
1284impl<'a> DefaultFunctionContext<'a> {
1285 pub fn new(
1286 base: &'a dyn EvaluationContext,
1287 current: Option<CellRef>,
1288 current_sheet: &'a str,
1289 ) -> Self {
1290 Self {
1291 base,
1292 current,
1293 current_sheet,
1294 }
1295 }
1296
1297 pub fn new_with_sheet(
1298 base: &'a dyn EvaluationContext,
1299 current: Option<CellRef>,
1300 current_sheet: &'a str,
1301 ) -> Self {
1302 Self::new(base, current, current_sheet)
1303 }
1304}
1305
1306impl<'a> FunctionContext<'a> for DefaultFunctionContext<'a> {
1307 fn locale(&self) -> crate::locale::Locale {
1308 self.base.locale()
1309 }
1310
1311 fn current_sheet(&self) -> &str {
1312 self.current_sheet
1313 }
1314 fn timezone(&self) -> &crate::timezone::TimeZoneSpec {
1315 self.base.timezone()
1316 }
1317 fn thread_pool(&self) -> Option<&std::sync::Arc<rayon::ThreadPool>> {
1318 self.base.thread_pool()
1319 }
1320 fn cancellation_token(&self) -> Option<Arc<std::sync::atomic::AtomicBool>> {
1321 self.base.cancellation_token()
1322 }
1323 fn chunk_hint(&self) -> Option<usize> {
1324 self.base.chunk_hint()
1325 }
1326
1327 fn volatile_level(&self) -> VolatileLevel {
1328 self.base.volatile_level()
1329 }
1330 fn workbook_seed(&self) -> u64 {
1331 self.base.workbook_seed()
1332 }
1333 fn recalc_epoch(&self) -> u64 {
1334 self.base.recalc_epoch()
1335 }
1336 fn current_cell(&self) -> Option<CellRef> {
1337 self.current
1338 }
1339
1340 fn resolve_range_view(
1341 &self,
1342 reference: &ReferenceType,
1343 current_sheet: &str,
1344 ) -> Result<RangeView<'a>, ExcelError> {
1345 self.base.resolve_range_view(reference, current_sheet)
1346 }
1347
1348 fn date_system(&self) -> crate::engine::DateSystem {
1351 self.base.date_system()
1352 }
1353
1354 fn get_criteria_mask(
1355 &self,
1356 view: &RangeView<'_>,
1357 col_in_view: usize,
1358 pred: &crate::args::CriteriaPredicate,
1359 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1360 self.base.build_criteria_mask(view, col_in_view, pred)
1361 }
1362}