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 enum EvaluatedArg<'a> {
86 LiteralValue(CowValue<'a>),
87 Range(Box<dyn Range>),
88}
89
90enum ArgumentExpr<'a> {
91 Ast(&'a ASTNode),
92 Arena {
93 id: crate::engine::arena::AstNodeId,
94 data_store: &'a crate::engine::arena::DataStore,
95 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
96 },
97}
98
99pub struct ArgumentHandle<'a, 'b> {
100 expr: ArgumentExpr<'a>,
101 interp: &'a Interpreter<'b>,
102 cached_ast: std::cell::OnceCell<ASTNode>,
103 cached_ref: std::cell::OnceCell<ReferenceType>,
104}
105
106impl<'a, 'b> ArgumentHandle<'a, 'b> {
107 pub(crate) fn new(node: &'a ASTNode, interp: &'a Interpreter<'b>) -> Self {
108 Self {
109 expr: ArgumentExpr::Ast(node),
110 interp,
111 cached_ast: std::cell::OnceCell::new(),
112 cached_ref: std::cell::OnceCell::new(),
113 }
114 }
115
116 pub(crate) fn new_arena(
117 id: crate::engine::arena::AstNodeId,
118 interp: &'a Interpreter<'b>,
119 data_store: &'a crate::engine::arena::DataStore,
120 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
121 ) -> Self {
122 Self {
123 expr: ArgumentExpr::Arena {
124 id,
125 data_store,
126 sheet_registry,
127 },
128 interp,
129 cached_ast: std::cell::OnceCell::new(),
130 cached_ref: std::cell::OnceCell::new(),
131 }
132 }
133
134 pub fn value(&self) -> Result<CowValue<'_>, ExcelError> {
135 match &self.expr {
136 ArgumentExpr::Ast(node) => {
137 if let ASTNodeType::Literal(ref v) = node.node_type {
138 return Ok(Cow::Borrowed(v));
139 }
140 self.interp.evaluate_ast(node).map(Cow::Owned)
141 }
142 ArgumentExpr::Arena {
143 id,
144 data_store,
145 sheet_registry,
146 } => self
147 .interp
148 .evaluate_arena_ast(*id, data_store, sheet_registry)
149 .map(Cow::Owned),
150 }
151 }
152
153 pub fn inline_array_literal(&self) -> Result<Option<Vec<Vec<LiteralValue>>>, ExcelError> {
154 match &self.expr {
155 ArgumentExpr::Ast(node) => match &node.node_type {
156 ASTNodeType::Literal(LiteralValue::Array(arr)) => Ok(Some(arr.clone())),
157 _ => Ok(None),
158 },
159 ArgumentExpr::Arena {
160 id,
161 data_store,
162 sheet_registry,
163 } => {
164 let node = data_store.get_node(*id).ok_or_else(|| {
165 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
166 })?;
167 match node {
168 crate::engine::arena::AstNodeData::Literal(vref) => {
169 match data_store.retrieve_value(*vref) {
170 LiteralValue::Array(arr) => Ok(Some(arr)),
171 _ => Ok(None),
172 }
173 }
174 _ => {
175 let _ = sheet_registry;
178 Ok(None)
179 }
180 }
181 }
182 }
183 }
184
185 fn reference_for_eval(&self) -> Result<ReferenceType, ExcelError> {
186 match &self.expr {
187 ArgumentExpr::Ast(node) => match &node.node_type {
188 ASTNodeType::Reference { reference, .. } => Ok(reference.clone()),
189 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
190 self.interp.evaluate_ast_as_reference(node)
191 }
192 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
193 .with_message("Expected a reference (by-ref argument)")),
194 },
195 ArgumentExpr::Arena {
196 id,
197 data_store,
198 sheet_registry,
199 } => {
200 let node = data_store.get_node(*id).ok_or_else(|| {
201 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
202 })?;
203 match node {
204 crate::engine::arena::AstNodeData::Reference { ref_type, .. } => Ok(
205 data_store.reconstruct_reference_type_for_eval(ref_type, sheet_registry)
206 ),
207 crate::engine::arena::AstNodeData::Function { .. }
208 | crate::engine::arena::AstNodeData::BinaryOp { .. } => self
209 .interp
210 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry),
211 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
212 .with_message("Expected a reference (by-ref argument)")),
213 }
214 }
215 }
216 }
217
218 pub fn range(&self) -> Result<Box<dyn Range>, ExcelError> {
219 match &self.expr {
220 ArgumentExpr::Ast(node) => match &node.node_type {
221 ASTNodeType::Reference { reference, .. } => {
222 let view = self
224 .interp
225 .context
226 .resolve_range_view(reference, self.interp.current_sheet())?;
227 let (rows, cols) = view.dims();
228 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
229 view.for_each_row(&mut |row| {
230 let row_data: Vec<LiteralValue> = (0..cols)
231 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
232 .collect();
233 out.push(row_data);
234 Ok(())
235 })?;
236 Ok(Box::new(InMemoryRange::new(out)))
237 }
238 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
239 let reference = self.reference_for_eval()?;
240 let view = self
241 .interp
242 .context
243 .resolve_range_view(&reference, self.interp.current_sheet())?;
244 let (rows, cols) = view.dims();
245 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
246 view.for_each_row(&mut |row| {
247 let row_data: Vec<LiteralValue> = (0..cols)
248 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
249 .collect();
250 out.push(row_data);
251 Ok(())
252 })?;
253 Ok(Box::new(InMemoryRange::new(out)))
254 }
255 ASTNodeType::Array(rows) => {
256 let mut materialized = Vec::new();
257 for row in rows {
258 let mut materialized_row = Vec::new();
259 for cell in row {
260 materialized_row.push(self.interp.evaluate_ast(cell)?);
261 }
262 materialized.push(materialized_row);
263 }
264 Ok(Box::new(InMemoryRange::new(materialized)))
265 }
266 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
267 .with_message(format!("Expected a range, got {:?}", node.node_type))),
268 },
269 ArgumentExpr::Arena { id, data_store, .. } => {
270 let node = data_store.get_node(*id).ok_or_else(|| {
271 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
272 })?;
273
274 match node {
275 crate::engine::arena::AstNodeData::Reference { .. }
276 | crate::engine::arena::AstNodeData::Function { .. }
277 | crate::engine::arena::AstNodeData::BinaryOp { .. } => {
278 let reference = self.reference_for_eval()?;
279 let view = self
280 .interp
281 .context
282 .resolve_range_view(&reference, self.interp.current_sheet())?;
283 let (rows, cols) = view.dims();
284 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows);
285 view.for_each_row(&mut |row| {
286 let row_data: Vec<LiteralValue> = (0..cols)
287 .map(|c| row.get(c).cloned().unwrap_or(LiteralValue::Empty))
288 .collect();
289 out.push(row_data);
290 Ok(())
291 })?;
292 Ok(Box::new(InMemoryRange::new(out)))
293 }
294 crate::engine::arena::AstNodeData::Array { .. } => {
295 let (rows, cols, elements) =
296 data_store.get_array_elems(*id).ok_or_else(|| {
297 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
298 })?;
299 let rows_usize = rows as usize;
300 let cols_usize = cols as usize;
301 let mut materialized: Vec<Vec<LiteralValue>> =
302 Vec::with_capacity(rows_usize);
303 for r in 0..rows_usize {
304 let mut row = Vec::with_capacity(cols_usize);
305 for c in 0..cols_usize {
306 let idx = r * cols_usize + c;
307 let elem_id = elements.get(idx).copied().ok_or_else(|| {
308 ExcelError::new(ExcelErrorKind::Value)
309 .with_message("Invalid array")
310 })?;
311 let v = self.interp.evaluate_arena_ast(
312 elem_id,
313 data_store,
314 self.sheet_registry(),
315 )?;
316 row.push(v);
317 }
318 materialized.push(row);
319 }
320 Ok(Box::new(InMemoryRange::new(materialized)))
321 }
322 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
323 .with_message("Argument cannot be interpreted as a range.")),
324 }
325 }
326 }
327 }
328
329 fn sheet_registry(&self) -> &crate::engine::sheet_registry::SheetRegistry {
330 match &self.expr {
331 ArgumentExpr::Ast(_) => {
332 unreachable!("sheet_registry only used for arena ArgumentHandle")
334 }
335 ArgumentExpr::Arena { sheet_registry, .. } => sheet_registry,
336 }
337 }
338
339 pub fn range_view(&self) -> Result<RangeView<'_>, ExcelError> {
341 match &self.expr {
342 ArgumentExpr::Ast(node) => match &node.node_type {
343 ASTNodeType::Reference { reference, .. } => self
344 .interp
345 .context
346 .resolve_range_view(reference, self.interp.current_sheet()),
347 ASTNodeType::Literal(formualizer_common::LiteralValue::Array(arr)) => {
349 Ok(RangeView::from_borrowed(&arr[..]))
351 }
352 ASTNodeType::Array(rows) => {
353 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows.len());
355 for r in rows {
356 let mut row_vals = Vec::with_capacity(r.len());
357 for cell in r {
358 row_vals.push(self.interp.evaluate_ast(cell)?);
359 }
360 out.push(row_vals);
361 }
362 Ok(RangeView::from_borrowed(Box::leak(Box::new(out))))
363 }
364 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
365 let reference = self.reference_for_eval()?;
366 self.interp
367 .context
368 .resolve_range_view(&reference, self.interp.current_sheet())
369 }
370 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
371 .with_message("Argument cannot be interpreted as a range.")),
372 },
373 ArgumentExpr::Arena {
374 id,
375 data_store,
376 sheet_registry,
377 } => {
378 let node = data_store.get_node(*id).ok_or_else(|| {
379 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
380 })?;
381
382 match node {
383 crate::engine::arena::AstNodeData::Reference { .. }
384 | crate::engine::arena::AstNodeData::Function { .. }
385 | crate::engine::arena::AstNodeData::BinaryOp { .. } => {
386 let reference = self.reference_for_eval()?;
387 self.interp
388 .context
389 .resolve_range_view(&reference, self.interp.current_sheet())
390 }
391 crate::engine::arena::AstNodeData::Literal(vref) => {
392 match data_store.retrieve_value(*vref) {
393 LiteralValue::Array(arr) => {
394 Ok(RangeView::from_borrowed(Box::leak(Box::new(arr))))
395 }
396 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
397 .with_message("Argument cannot be interpreted as a range.")),
398 }
399 }
400 crate::engine::arena::AstNodeData::Array { .. } => {
401 let (rows, cols, elements) =
402 data_store.get_array_elems(*id).ok_or_else(|| {
403 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
404 })?;
405
406 let rows_usize = rows as usize;
407 let cols_usize = cols as usize;
408 let mut out: Vec<Vec<LiteralValue>> = Vec::with_capacity(rows_usize);
409 for r in 0..rows_usize {
410 let mut row = Vec::with_capacity(cols_usize);
411 for c in 0..cols_usize {
412 let idx = r * cols_usize + c;
413 let elem_id = elements.get(idx).copied().ok_or_else(|| {
414 ExcelError::new(ExcelErrorKind::Value)
415 .with_message("Invalid array")
416 })?;
417 let v = self.interp.evaluate_arena_ast(
418 elem_id,
419 data_store,
420 sheet_registry,
421 )?;
422 row.push(v);
423 }
424 out.push(row);
425 }
426 Ok(RangeView::from_borrowed(Box::leak(Box::new(out))))
427 }
428 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
429 .with_message("Argument cannot be interpreted as a range.")),
430 }
431 }
432 }
433 }
434
435 pub fn value_or_range(&self) -> Result<EvaluatedArg<'_>, ExcelError> {
436 self.range()
437 .map(EvaluatedArg::Range)
438 .or_else(|_| self.value().map(EvaluatedArg::LiteralValue))
439 }
440
441 pub fn lazy_values_owned(
446 &'a self,
447 ) -> Result<Box<dyn Iterator<Item = LiteralValue> + 'a>, ExcelError> {
448 match &self.expr {
449 ArgumentExpr::Ast(node) => match &node.node_type {
450 ASTNodeType::Reference { .. } => {
451 let view = self.range_view()?;
452 let mut values: Vec<LiteralValue> = Vec::new();
453 view.for_each_cell(&mut |v| {
454 values.push(v.clone());
455 Ok(())
456 })?;
457 Ok(Box::new(values.into_iter()))
458 }
459 ASTNodeType::Array(rows) => {
460 struct ArrayEvalIter<'a, 'b> {
461 rows: &'a [Vec<ASTNode>],
462 r: usize,
463 c: usize,
464 interp: &'a Interpreter<'b>,
465 }
466 impl<'a, 'b> Iterator for ArrayEvalIter<'a, 'b> {
467 type Item = LiteralValue;
468 fn next(&mut self) -> Option<Self::Item> {
469 if self.rows.is_empty() {
470 return None;
471 }
472 let rows = self.rows;
473 let mut r = self.r;
474 let mut c = self.c;
475 if r >= rows.len() {
476 return None;
477 }
478 let node = &rows[r][c];
479 c += 1;
481 if c >= rows[r].len() {
482 r += 1;
483 c = 0;
484 }
485 self.r = r;
486 self.c = c;
487 match self.interp.evaluate_ast(node) {
488 Ok(v) => Some(v),
489 Err(e) => Some(LiteralValue::Error(e)),
490 }
491 }
492 }
493 let it = ArrayEvalIter {
494 rows,
495 r: 0,
496 c: 0,
497 interp: self.interp,
498 };
499 Ok(Box::new(it))
500 }
501 _ => {
502 let v = self.value()?.into_owned();
504 Ok(Box::new(std::iter::once(v)))
505 }
506 },
507 ArgumentExpr::Arena {
508 id,
509 data_store,
510 sheet_registry,
511 } => {
512 let node = data_store.get_node(*id).ok_or_else(|| {
513 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
514 })?;
515
516 match node {
517 crate::engine::arena::AstNodeData::Reference { .. } => {
518 let view = self.range_view()?;
519 let mut values: Vec<LiteralValue> = Vec::new();
520 view.for_each_cell(&mut |v| {
521 values.push(v.clone());
522 Ok(())
523 })?;
524 Ok(Box::new(values.into_iter()))
525 }
526 crate::engine::arena::AstNodeData::Array { .. } => {
527 let (rows, cols, elements) =
528 data_store.get_array_elems(*id).ok_or_else(|| {
529 ExcelError::new(ExcelErrorKind::Value).with_message("Invalid array")
530 })?;
531
532 struct ArenaArrayEvalIter<'a, 'b> {
533 elements: &'a [crate::engine::arena::AstNodeId],
534 idx: usize,
535 interp: &'a Interpreter<'b>,
536 data_store: &'a crate::engine::arena::DataStore,
537 sheet_registry: &'a crate::engine::sheet_registry::SheetRegistry,
538 }
539
540 impl<'a, 'b> Iterator for ArenaArrayEvalIter<'a, 'b> {
541 type Item = LiteralValue;
542
543 fn next(&mut self) -> Option<Self::Item> {
544 let id = self.elements.get(self.idx).copied()?;
545 self.idx += 1;
546 match self.interp.evaluate_arena_ast(
547 id,
548 self.data_store,
549 self.sheet_registry,
550 ) {
551 Ok(v) => Some(v),
552 Err(e) => Some(LiteralValue::Error(e)),
553 }
554 }
555 }
556
557 let _ = (rows, cols);
558 let it = ArenaArrayEvalIter {
559 elements,
560 idx: 0,
561 interp: self.interp,
562 data_store,
563 sheet_registry,
564 };
565 Ok(Box::new(it))
566 }
567 _ => {
568 let v = self
569 .interp
570 .evaluate_arena_ast(*id, data_store, sheet_registry)?;
571 Ok(Box::new(std::iter::once(v)))
572 }
573 }
574 }
575 }
576 }
577
578 pub fn ast(&self) -> &ASTNode {
579 match &self.expr {
580 ArgumentExpr::Ast(node) => node,
581 ArgumentExpr::Arena {
582 id,
583 data_store,
584 sheet_registry,
585 } => self.cached_ast.get_or_init(|| {
586 data_store
587 .retrieve_ast(*id, sheet_registry)
588 .unwrap_or_else(|| ASTNode {
589 node_type: ASTNodeType::Literal(LiteralValue::Error(
590 ExcelError::new(ExcelErrorKind::Value)
591 .with_message("Missing formula AST"),
592 )),
593 source_token: None,
594 contains_volatile: false,
595 })
596 }),
597 }
598 }
599
600 pub fn as_reference(&self) -> Result<&ReferenceType, ExcelError> {
603 match &self.expr {
604 ArgumentExpr::Ast(node) => match &node.node_type {
605 ASTNodeType::Reference { reference, .. } => Ok(reference),
606 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
607 .with_message("Expected a reference (by-ref argument)")),
608 },
609 ArgumentExpr::Arena { .. } => {
610 let reference = self.reference_for_eval()?;
611 Ok(self.cached_ref.get_or_init(|| reference))
612 }
613 }
614 }
615
616 pub fn as_reference_or_eval(&self) -> Result<ReferenceType, ExcelError> {
619 match &self.expr {
620 ArgumentExpr::Ast(node) => match &node.node_type {
621 ASTNodeType::Reference { reference, .. } => Ok(reference.clone()),
622 ASTNodeType::Function { .. } | ASTNodeType::BinaryOp { .. } => {
623 self.interp.evaluate_ast_as_reference(node)
624 }
625 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
626 .with_message("Argument is not a reference")),
627 },
628 ArgumentExpr::Arena {
629 id,
630 data_store,
631 sheet_registry,
632 } => {
633 let node = data_store.get_node(*id).ok_or_else(|| {
634 ExcelError::new(ExcelErrorKind::Value).with_message("Missing AST node")
635 })?;
636
637 match node {
638 crate::engine::arena::AstNodeData::Reference { .. } => {
639 self.reference_for_eval()
640 }
641 crate::engine::arena::AstNodeData::Function { .. }
642 | crate::engine::arena::AstNodeData::BinaryOp { .. } => self
643 .interp
644 .evaluate_arena_ast_as_reference(*id, data_store, sheet_registry),
645 _ => Err(ExcelError::new(ExcelErrorKind::Ref)
646 .with_message("Argument is not a reference")),
647 }
648 }
649 }
650 }
651
652 pub fn matches_kind(&self, k: formualizer_common::ArgKind) -> Result<bool, ExcelError> {
654 Ok(match k {
655 formualizer_common::ArgKind::Any => true,
656 formualizer_common::ArgKind::Range => self.range().is_ok(),
657 formualizer_common::ArgKind::Number => matches!(
658 self.value()?.as_ref(),
659 LiteralValue::Number(_) | LiteralValue::Int(_)
660 ),
661 formualizer_common::ArgKind::Text => {
662 matches!(self.value()?.as_ref(), LiteralValue::Text(_))
663 }
664 formualizer_common::ArgKind::Logical => {
665 matches!(self.value()?.as_ref(), LiteralValue::Boolean(_))
666 }
667 })
668 }
669}
670
671#[derive(Debug, Clone)]
673pub struct InMemoryRange {
674 data: Vec<Vec<LiteralValue>>,
675}
676impl InMemoryRange {
677 pub fn new(d: Vec<Vec<LiteralValue>>) -> Self {
678 Self { data: d }
679 }
680}
681impl Range for InMemoryRange {
682 fn get(&self, r: usize, c: usize) -> Result<LiteralValue, ExcelError> {
683 Ok(self
684 .data
685 .get(r)
686 .and_then(|row| row.get(c))
687 .cloned()
688 .unwrap_or(LiteralValue::Empty))
689 }
690 fn dimensions(&self) -> (usize, usize) {
691 (self.data.len(), self.data.first().map_or(0, |r| r.len()))
692 }
693 fn as_any(&self) -> &dyn Any {
694 self
695 }
696}
697
698pub trait Table: Debug + Send + Sync {
701 fn get_cell(&self, row: usize, column: &str) -> Result<LiteralValue, ExcelError>;
702 fn get_column(&self, column: &str) -> Result<Box<dyn Range>, ExcelError>;
703 fn columns(&self) -> Vec<String> {
705 vec![]
706 }
707 fn data_height(&self) -> usize {
709 0
710 }
711 fn has_headers(&self) -> bool {
713 false
714 }
715 fn has_totals(&self) -> bool {
717 false
718 }
719 fn headers_row(&self) -> Option<Box<dyn Range>> {
721 None
722 }
723 fn totals_row(&self) -> Option<Box<dyn Range>> {
725 None
726 }
727 fn data_body(&self) -> Option<Box<dyn Range>> {
729 None
730 }
731 fn clone_box(&self) -> Box<dyn Table>;
732}
733impl Table for Box<dyn Table> {
734 fn get_cell(&self, r: usize, c: &str) -> Result<LiteralValue, ExcelError> {
735 (**self).get_cell(r, c)
736 }
737 fn get_column(&self, c: &str) -> Result<Box<dyn Range>, ExcelError> {
738 (**self).get_column(c)
739 }
740 fn columns(&self) -> Vec<String> {
741 (**self).columns()
742 }
743 fn data_height(&self) -> usize {
744 (**self).data_height()
745 }
746 fn has_headers(&self) -> bool {
747 (**self).has_headers()
748 }
749 fn has_totals(&self) -> bool {
750 (**self).has_totals()
751 }
752 fn headers_row(&self) -> Option<Box<dyn Range>> {
753 (**self).headers_row()
754 }
755 fn totals_row(&self) -> Option<Box<dyn Range>> {
756 (**self).totals_row()
757 }
758 fn data_body(&self) -> Option<Box<dyn Range>> {
759 (**self).data_body()
760 }
761 fn clone_box(&self) -> Box<dyn Table> {
762 (**self).clone_box()
763 }
764}
765
766pub trait ReferenceResolver: Send + Sync {
769 fn resolve_cell_reference(
770 &self,
771 sheet: Option<&str>,
772 row: u32,
773 col: u32,
774 ) -> Result<LiteralValue, ExcelError>;
775}
776pub trait RangeResolver: Send + Sync {
777 fn resolve_range_reference(
778 &self,
779 sheet: Option<&str>,
780 sr: Option<u32>,
781 sc: Option<u32>,
782 er: Option<u32>,
783 ec: Option<u32>,
784 ) -> Result<Box<dyn Range>, ExcelError>;
785}
786pub trait NamedRangeResolver: Send + Sync {
787 fn resolve_named_range_reference(
788 &self,
789 name: &str,
790 ) -> Result<Vec<Vec<LiteralValue>>, ExcelError>;
791}
792pub trait TableResolver: Send + Sync {
793 fn resolve_table_reference(
794 &self,
795 tref: &formualizer_parse::parser::TableReference,
796 ) -> Result<Box<dyn Table>, ExcelError>;
797}
798pub trait Resolver: ReferenceResolver + RangeResolver + NamedRangeResolver + TableResolver {
799 fn resolve_range_like(&self, r: &ReferenceType) -> Result<Box<dyn Range>, ExcelError> {
800 match r {
801 ReferenceType::Range {
802 sheet,
803 start_row,
804 start_col,
805 end_row,
806 end_col,
807 } => self.resolve_range_reference(
808 sheet.as_deref(),
809 *start_row,
810 *start_col,
811 *end_row,
812 *end_col,
813 ),
814 ReferenceType::Table(tref) => {
815 let t = self.resolve_table_reference(tref)?;
816 match &tref.specifier {
817 Some(TableSpecifier::Column(c)) => t.get_column(c),
818 Some(TableSpecifier::ColumnRange(start, end)) => {
819 let cols = t.columns();
821 let start_idx = cols.iter().position(|n| n.eq_ignore_ascii_case(start));
822 let end_idx = cols.iter().position(|n| n.eq_ignore_ascii_case(end));
823 if let (Some(mut si), Some(mut ei)) = (start_idx, end_idx) {
824 if si > ei {
825 std::mem::swap(&mut si, &mut ei);
826 }
827 let h = t.data_height();
829 let w = ei - si + 1;
830 let mut rows = vec![vec![LiteralValue::Empty; w]; h];
831 for (offset, ci) in (si..=ei).enumerate() {
832 let cname = &cols[ci];
833 let col_range = t.get_column(cname)?;
834 let (rh, _) = col_range.dimensions();
835 for (r, row) in rows.iter_mut().enumerate().take(h.min(rh)) {
836 row[offset] = col_range.get(r, 0)?;
837 }
838 }
839 Ok(Box::new(InMemoryRange::new(rows)))
840 } else {
841 Err(ExcelError::new(ExcelErrorKind::Ref).with_message(
842 "Column range refers to unknown column(s)".to_string(),
843 ))
844 }
845 }
846 Some(TableSpecifier::SpecialItem(
847 formualizer_parse::parser::SpecialItem::Headers,
848 )) => {
849 if let Some(h) = t.headers_row() {
850 Ok(h)
851 } else {
852 Ok(Box::new(InMemoryRange::new(vec![])))
853 }
854 }
855 Some(TableSpecifier::SpecialItem(
856 formualizer_parse::parser::SpecialItem::Totals,
857 )) => {
858 if let Some(tr) = t.totals_row() {
859 Ok(tr)
860 } else {
861 Ok(Box::new(InMemoryRange::new(vec![])))
862 }
863 }
864 Some(TableSpecifier::SpecialItem(
865 formualizer_parse::parser::SpecialItem::Data,
866 )) => {
867 if let Some(body) = t.data_body() {
868 Ok(body)
869 } else {
870 Ok(Box::new(InMemoryRange::new(vec![])))
871 }
872 }
873 Some(TableSpecifier::SpecialItem(
874 formualizer_parse::parser::SpecialItem::All,
875 )) => {
876 let mut out: Vec<Vec<LiteralValue>> = Vec::new();
878 if let Some(h) = t.headers_row() {
879 out.extend(h.iter_rows());
880 }
881 if let Some(body) = t.data_body() {
882 out.extend(body.iter_rows());
883 }
884 if let Some(tr) = t.totals_row() {
885 out.extend(tr.iter_rows());
886 }
887 Ok(Box::new(InMemoryRange::new(out)))
888 }
889 Some(TableSpecifier::SpecialItem(
890 formualizer_parse::parser::SpecialItem::ThisRow,
891 )) => Err(ExcelError::new(ExcelErrorKind::NImpl).with_message(
892 "@ (This Row) requires table-aware context; not yet supported".to_string(),
893 )),
894 Some(TableSpecifier::All) => {
895 let mut out: Vec<Vec<LiteralValue>> = Vec::new();
897 if let Some(h) = t.headers_row() {
898 out.extend(h.iter_rows());
899 }
900 if let Some(body) = t.data_body() {
901 out.extend(body.iter_rows());
902 }
903 if let Some(tr) = t.totals_row() {
904 out.extend(tr.iter_rows());
905 }
906 Ok(Box::new(InMemoryRange::new(out)))
907 }
908 Some(TableSpecifier::Data) => {
909 if let Some(body) = t.data_body() {
910 Ok(body)
911 } else {
912 Ok(Box::new(InMemoryRange::new(vec![])))
913 }
914 }
915 Some(TableSpecifier::Combination(_)) => Err(ExcelError::new(
917 ExcelErrorKind::NImpl,
918 )
919 .with_message("Complex structured references not yet supported".to_string())),
920 Some(TableSpecifier::Row(_)) => Err(ExcelError::new(ExcelErrorKind::NImpl)
921 .with_message("Row selectors (@/index) not yet supported".to_string())),
922 Some(TableSpecifier::Headers) | Some(TableSpecifier::Totals) => {
923 Err(ExcelError::new(ExcelErrorKind::NImpl).with_message(
924 "Legacy Headers/Totals variants not used; use SpecialItem".to_string(),
925 ))
926 }
927 None => Err(ExcelError::new(ExcelErrorKind::Ref).with_message(
928 "Table reference without specifier is unsupported".to_string(),
929 )),
930 }
931 }
932 ReferenceType::NamedRange(n) => {
933 let v = self.resolve_named_range_reference(n)?;
934 Ok(Box::new(InMemoryRange::new(v)))
935 }
936 ReferenceType::Cell { sheet, row, col } => {
937 let v = self.resolve_cell_reference(sheet.as_deref(), *row, *col)?;
938 Ok(Box::new(InMemoryRange::new(vec![vec![v]])))
939 }
940 }
941 }
942}
943
944pub trait FunctionProvider: Send + Sync {
947 fn get_function(&self, ns: &str, name: &str) -> Option<Arc<dyn Function>>;
948}
949
950pub trait EvaluationContext: Resolver + FunctionProvider {
951 fn thread_pool(&self) -> Option<&Arc<rayon::ThreadPool>> {
954 None
955 }
956
957 fn cancellation_token(&self) -> Option<&std::sync::atomic::AtomicBool> {
959 None
960 }
961
962 fn chunk_hint(&self) -> Option<usize> {
964 None
965 }
966
967 fn resolve_range_view<'c>(
970 &'c self,
971 _reference: &ReferenceType,
972 _current_sheet: &str,
973 ) -> Result<RangeView<'c>, ExcelError> {
974 Err(ExcelError::new(ExcelErrorKind::NImpl))
975 }
976
977 fn locale(&self) -> crate::locale::Locale {
979 crate::locale::Locale::invariant()
980 }
981
982 fn timezone(&self) -> &crate::timezone::TimeZoneSpec {
986 static DEFAULT_TZ: std::sync::OnceLock<crate::timezone::TimeZoneSpec> =
988 std::sync::OnceLock::new();
989 DEFAULT_TZ.get_or_init(crate::timezone::TimeZoneSpec::default)
990 }
991
992 fn volatile_level(&self) -> VolatileLevel {
994 VolatileLevel::Always
995 }
996
997 fn workbook_seed(&self) -> u64 {
999 0xF0F0_D0D0_AAAA_5555
1000 }
1001
1002 fn recalc_epoch(&self) -> u64 {
1004 0
1005 }
1006
1007 fn used_rows_for_columns(
1012 &self,
1013 _sheet: &str,
1014 _start_col: u32,
1015 _end_col: u32,
1016 ) -> Option<(u32, u32)> {
1017 None
1018 }
1019
1020 fn used_cols_for_rows(
1023 &self,
1024 _sheet: &str,
1025 _start_row: u32,
1026 _end_row: u32,
1027 ) -> Option<(u32, u32)> {
1028 None
1029 }
1030
1031 fn sheet_bounds(&self, _sheet: &str) -> Option<(u32, u32)> {
1033 None
1034 }
1035
1036 fn data_snapshot_id(&self) -> u64 {
1038 0
1039 }
1040
1041 fn backend_caps(&self) -> BackendCaps {
1043 BackendCaps::default()
1044 }
1045
1046 fn arrow_fastpath_enabled(&self) -> bool {
1051 false
1052 }
1053
1054 fn date_system(&self) -> crate::engine::DateSystem {
1057 crate::engine::DateSystem::Excel1900
1058 }
1059
1060 fn build_criteria_mask(
1063 &self,
1064 _view: &crate::arrow_store::ArrowRangeView<'_>,
1065 _col_in_view: usize,
1066 _pred: &crate::args::CriteriaPredicate,
1067 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1068 None
1069 }
1070}
1071
1072#[derive(Copy, Clone, Debug, Default)]
1074pub struct BackendCaps {
1075 pub streaming: bool,
1077 pub used_region: bool,
1079 pub write: bool,
1081 pub tables: bool,
1083 pub async_stream: bool,
1085}
1086
1087#[derive(Copy, Clone, Debug, Eq, PartialEq)]
1090pub enum VolatileLevel {
1091 Always,
1093 OnRecalc,
1095 OnOpen,
1097}
1098
1099pub trait FunctionContext {
1101 fn locale(&self) -> crate::locale::Locale;
1102 fn timezone(&self) -> &crate::timezone::TimeZoneSpec;
1103 fn thread_pool(&self) -> Option<&std::sync::Arc<rayon::ThreadPool>>;
1104 fn cancellation_token(&self) -> Option<&std::sync::atomic::AtomicBool>;
1105 fn chunk_hint(&self) -> Option<usize>;
1106
1107 fn current_sheet(&self) -> &str;
1109
1110 fn volatile_level(&self) -> VolatileLevel;
1111 fn workbook_seed(&self) -> u64;
1112 fn recalc_epoch(&self) -> u64;
1113 fn current_cell(&self) -> Option<CellRef>;
1114
1115 fn resolve_range_view<'c>(
1117 &'c self,
1118 _reference: &ReferenceType,
1119 _current_sheet: &str,
1120 ) -> Result<RangeView<'c>, ExcelError> {
1121 Err(ExcelError::new(ExcelErrorKind::NImpl))
1122 }
1123
1124 fn rng_for_current(&self, fn_salt: u64) -> rand::rngs::SmallRng {
1128 use crate::rng::{compose_seed, small_rng_from_lanes};
1129 let (sheet_id, row, col) = self
1130 .current_cell()
1131 .map(|c| (c.sheet_id as u32, c.coord.row(), c.coord.col()))
1132 .unwrap_or((0, 0, 0));
1133 let epoch = match self.volatile_level() {
1135 VolatileLevel::OnRecalc => self.recalc_epoch(),
1136 _ => 0,
1137 };
1138 let (l0, l1) = compose_seed(self.workbook_seed(), sheet_id, row, col, fn_salt, epoch);
1139 small_rng_from_lanes(l0, l1)
1140 }
1141
1142 fn arrow_fastpath_enabled(&self) -> bool {
1144 false
1145 }
1146
1147 fn date_system(&self) -> crate::engine::DateSystem {
1149 crate::engine::DateSystem::Excel1900
1150 }
1151
1152 fn get_criteria_mask(
1155 &self,
1156 _view: &crate::arrow_store::ArrowRangeView<'_>,
1157 _col_in_view: usize,
1158 _pred: &crate::args::CriteriaPredicate,
1159 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1160 None
1161 }
1162}
1163
1164pub struct DefaultFunctionContext<'a> {
1166 pub base: &'a dyn EvaluationContext,
1167 pub current: Option<CellRef>,
1168 pub current_sheet: &'a str,
1169}
1170
1171impl<'a> DefaultFunctionContext<'a> {
1172 pub fn new(
1173 base: &'a dyn EvaluationContext,
1174 current: Option<CellRef>,
1175 current_sheet: &'a str,
1176 ) -> Self {
1177 Self {
1178 base,
1179 current,
1180 current_sheet,
1181 }
1182 }
1183
1184 pub fn new_with_sheet(
1185 base: &'a dyn EvaluationContext,
1186 current: Option<CellRef>,
1187 current_sheet: &'a str,
1188 ) -> Self {
1189 Self::new(base, current, current_sheet)
1190 }
1191}
1192
1193impl<'a> FunctionContext for DefaultFunctionContext<'a> {
1194 fn locale(&self) -> crate::locale::Locale {
1195 self.base.locale()
1196 }
1197
1198 fn current_sheet(&self) -> &str {
1199 self.current_sheet
1200 }
1201 fn timezone(&self) -> &crate::timezone::TimeZoneSpec {
1202 self.base.timezone()
1203 }
1204 fn thread_pool(&self) -> Option<&std::sync::Arc<rayon::ThreadPool>> {
1205 self.base.thread_pool()
1206 }
1207 fn cancellation_token(&self) -> Option<&std::sync::atomic::AtomicBool> {
1208 self.base.cancellation_token()
1209 }
1210 fn chunk_hint(&self) -> Option<usize> {
1211 self.base.chunk_hint()
1212 }
1213
1214 fn volatile_level(&self) -> VolatileLevel {
1215 self.base.volatile_level()
1216 }
1217 fn workbook_seed(&self) -> u64 {
1218 self.base.workbook_seed()
1219 }
1220 fn recalc_epoch(&self) -> u64 {
1221 self.base.recalc_epoch()
1222 }
1223 fn current_cell(&self) -> Option<CellRef> {
1224 self.current
1225 }
1226
1227 fn resolve_range_view<'c>(
1228 &'c self,
1229 reference: &ReferenceType,
1230 current_sheet: &str,
1231 ) -> Result<RangeView<'c>, ExcelError> {
1232 self.base.resolve_range_view(reference, current_sheet)
1233 }
1234
1235 fn arrow_fastpath_enabled(&self) -> bool {
1238 self.base.arrow_fastpath_enabled()
1239 }
1240
1241 fn date_system(&self) -> crate::engine::DateSystem {
1242 self.base.date_system()
1243 }
1244
1245 fn get_criteria_mask(
1246 &self,
1247 view: &crate::arrow_store::ArrowRangeView<'_>,
1248 col_in_view: usize,
1249 pred: &crate::args::CriteriaPredicate,
1250 ) -> Option<std::sync::Arc<arrow_array::BooleanArray>> {
1251 self.base.build_criteria_mask(view, col_in_view, pred)
1252 }
1253}