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