1use petgraph::{
2 graphmap::DiGraphMap,
3 algo::toposort,
4 dot::{Dot, Config}
5};
6use std::{fmt, cmp::Ordering};
7use crate::{
8 workbook::Sheet,
9 parser::{
10 parse_str,
11 ast::Expr
12 },
13 reference::Reference,
14 errors::Error,
15};
16
17#[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)]
18pub struct CellId {
19 pub sheet: usize,
20 pub row: usize,
21 pub column: usize,
22 pub num_row: usize,
23 pub num_col: usize,
24 pub calculated: Option<bool>
25}
26
27impl PartialOrd for CellId {
28 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
29 Some(self.cmp(other))
30 }
31}
32
33impl Ord for CellId {
34 fn cmp(&self, other: &Self) -> Ordering {
35 if self.sheet == other.sheet {
36 if self.row != other.row {
37 self.row.cmp(&other.row)
38 } else {
39 self.column.cmp(&other.column)
40 }
41 } else {
42 self.sheet.cmp(&other.sheet)
43 }
44 }
45}
46
47impl From<(usize, usize, usize, usize, usize, Option<bool>)> for CellId {
48 fn from((sheet, row, column, num_row, num_col, calculated) : (usize, usize, usize, usize, usize, Option<bool>)) -> CellId {
49 CellId { sheet, row, column, num_row, num_col, calculated }
50 }
51}
52
53impl fmt::Display for CellId {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 write!(f, "{}.{}.{}", self.sheet, self.row, self.column)
56 }
57}
58
59pub struct DependencyTree {
60 tree: DiGraphMap<CellId, u8>,
61 pub offsets: Vec<CellId>
62}
63
64impl Default for DependencyTree {
71 fn default() -> Self {
72 Self::new()
73 }
74}
75
76impl DependencyTree {
77 pub fn new() -> DependencyTree {
78 DependencyTree { tree: DiGraphMap::new(), offsets: vec![] }
79 }
80
81 pub fn add_formula(&mut self, cell: CellId, formula_text: &str, sheets: &Vec<Sheet>) -> Result<(), Error> {
82 let mut chars = formula_text.chars();
83 chars.next(); let expression: Expr = parse_str(chars.as_str())?;
85 self.add_expression(cell, expression, sheets)?;
86 Ok(())
87 }
88
89 pub fn add_expression(&mut self, cell: CellId, expression: Expr, sheets: &Vec<Sheet>) -> Result<(), Error> {
90 match expression {
91 Expr::Reference { sheet, reference } => {
92 let sheet_id = match sheet {
93 Some(s) => {
94 sheets.iter().position(|x| {
95 x.name == s
96 }).unwrap()
97 },
98 None => cell.sheet
99 };
100 let sheet: &Sheet = sheets.get(sheet_id).unwrap();
101 let reference = Reference::from(reference);
102 let (mut start_row, mut start_col, mut num_rows, mut num_cols) = reference.get_dimensions();
103 start_row = start_row.max(1);
104 start_col = start_col.max(1);
105 num_rows = num_rows.min(sheet.max_rows);
106 num_cols = num_cols.min(sheet.max_columns);
107 let pre_cell: CellId;
108 if reference.is_multi_cell() {
109 pre_cell = CellId::from((sheet_id, start_row, start_col, num_rows, num_cols, None));
110 if ! self.cell_exists(&pre_cell) {
111 for c in Reference::get_cells_from_dim(start_row, start_col, num_rows, num_cols) {
112 let sub_cell = CellId::from((sheet_id, c.0, c.1, 1, 1, Some(false)));
113 if sub_cell != pre_cell {
114 self.add_precedent(&sub_cell, &pre_cell);
115 }
116 }
117 }
118 } else {
119 pre_cell = CellId::from((sheet_id, start_row, start_col, num_rows, num_cols, Some(false)));
120 }
121 if pre_cell != cell {
122 self.add_precedent(&pre_cell, &cell);
123 }
124 },
125 Expr::Infix(_, a, b) => {
126 self.add_expression(cell, *a, sheets)?;
127 self.add_expression(cell, *b, sheets)?;
128 },
129 Expr::Prefix(_, a) => {
130 self.add_expression(cell, *a, sheets)?;
131 },
132 Expr::Func { name, args } => {
133 if name.as_str() == "OFFSET" {
134 let mut offset_args = args.clone();
135 offset_args.remove(0);
136 self.add_expression(cell, Expr::Array(offset_args), sheets)?;
137 }
138 for arg in args.into_iter() {
139 self.add_expression(cell, arg, sheets)?;
140 }
141 },
142 Expr::Array(arr) => {
143 for a in arr.into_iter() {
144 self.add_expression(cell, a, sheets)?;
145 }
146 },
147 _ => {}
148
149 }
150 Ok(())
151 }
152
153 pub fn add_cell(&mut self, cell: CellId) {
154 self.tree.add_node(cell);
155 }
156
157 pub fn cell_exists(&self, cell: &CellId) -> bool {
158 self.tree.contains_node(*cell)
159 }
160
161 pub fn add_cell_if_missing(&mut self, cell: &CellId) {
162 if self.tree.contains_node(*cell) {
163 self.add_cell(*cell);
164 }
165 }
166
167 pub fn add_precedent(&mut self, precedent: &CellId, cell: &CellId) {
168 self.add_cell_if_missing(precedent);
169 self.add_cell_if_missing(cell);
170 if !self.tree.contains_edge(*cell, *precedent) {
171 self.tree.add_edge(*precedent, *cell, 0);
172 }
173 }
174
175 pub fn is_precedent_of(&self, cell1: &CellId, cell2: &CellId) -> bool {
176 self.tree.contains_edge(*cell1, *cell2)
177 }
178
179 pub fn is_dependent_of(&self, cell1: &CellId, cell2: &CellId) -> bool {
180 self.tree.contains_edge(*cell2, *cell1)
181 }
182
183 pub fn get_order(&self) -> Vec<CellId> {
184 match toposort(&self.tree, None) {
185 Ok(order) => {
186 order
187 },
189 Err(e) => panic!("{:?}", e)
190 }
191 }
192}
193
194impl fmt::Display for DependencyTree {
195 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
196 write!(f, "{}", Dot::with_config(&self.tree, &[Config::EdgeNoLabel]))
197 }
198}
199
200#[cfg(test)]
201mod tests {
202 use crate::dependency::*;
203
204 #[test]
205 fn test_precedent() {
206 let mut tree = DependencyTree::new();
207 let a = CellId::from((0,0,0,1,1, Some(false)));
208 let b = CellId::from((1,0,0,1,1, Some(false)));
209 let c = CellId::from((2,0,0,1,1, Some(false)));
210 tree.add_precedent(&a, &b); tree.add_precedent(&c, &b); assert!(tree.is_dependent_of(&b, &a));
213 assert_eq!(tree.is_dependent_of(&a, &b), false);
214 }
215
216 #[test]
217 fn test_order() {
218 let mut tree = DependencyTree::new();
219 let a = CellId::from((0,0,0,1,1, Some(false)));
220 let b = CellId::from((1,0,0,1,1, Some(false)));
221 let c = CellId::from((2,0,0,1,1, Some(false)));
222 tree.add_precedent(&a, &b); tree.add_precedent(&b, &c); let mut order: Vec<CellId> = tree.get_order();
225 assert_eq!(order.pop().unwrap(), c);
226 assert_eq!(order.pop().unwrap(), b);
227 assert_eq!(order.pop().unwrap(), a);
228 }
229}
230