logisheets_parser/
reference.rs

1use crate::{
2    ast::{CubeDisplay, ExtRefDisplay, RangeDisplay},
3    context::ContextTrait,
4    errors::ParseError,
5};
6
7use super::ast;
8use super::Result;
9
10use logisheets_base::{
11    column_label_to_index, id_fetcher::IdFetcherTrait, Addr, BlockRange, CellId, Cube, CubeCross,
12    ExtRef, NormalRange, Range, RefAbs, SheetId,
13};
14use logisheets_lexer::*;
15use pest::iterators::Pair;
16use regex::Regex;
17
18lazy_static! {
19    static ref NUM_REGEX: Regex =
20        Regex::new(r#"([0-9]+)?(\.?([0-9]+))?([Ee]([+-]?[0-9]+))?"#).unwrap();
21    static ref WORKSHEET_PREIFX_REGEX: Regex =
22        Regex::new(r#"'?(\[(.+?)\])?((.+?):)?(.+?)'?!"#).unwrap();
23    static ref COLUMN_REGEX: Regex = Regex::new(r#"(\$)?([A-Z]+)"#).unwrap();
24    static ref ROW_REGEX: Regex = Regex::new(r#"(\$)?([0-9]+)"#).unwrap();
25}
26
27pub fn build_cell_reference<T>(
28    pair: Pair<Rule>,
29    curr_sheet: SheetId,
30    context: &mut T,
31) -> Result<ast::PureNode>
32where
33    T: ContextTrait,
34{
35    let mut pairs = pair.into_inner();
36    let p = pairs.next().unwrap();
37    let id_fetcher = context;
38    let r = match p.as_rule() {
39        Rule::a1_reference_with_prefix => build_a1_reference_with_prefix(p, curr_sheet, id_fetcher),
40        Rule::a1_reference_range_with_prefix => {
41            build_a1_reference_range_with_prefix(p, curr_sheet, id_fetcher)
42        }
43        _ => unreachable!(),
44    }?;
45    Ok(ast::PureNode::Reference(r))
46}
47
48fn build_a1_reference_range_with_prefix<T>(
49    pair: Pair<Rule>,
50    curr_sheet: SheetId,
51    id_fetcher: &mut T,
52) -> Result<ast::CellReference>
53where
54    T: ContextTrait,
55{
56    let mut iter = pair.into_inner();
57    let first = iter.next().unwrap();
58    let build_mut_ref_range =
59        |pair: Pair<Rule>, sheet_id: SheetId, id_fetcher: &mut T| -> Result<ast::CellReference> {
60            let a1_ref = build_mut_a1_reference_range(pair, sheet_id, id_fetcher)?;
61            let start = a1_ref.start;
62            let end = a1_ref.end;
63            let ref_abs =
64                RefAbs::from_addr_range(start.row_abs, end.row_abs, start.col_abs, end.col_abs);
65            match (start.cell_id, end.cell_id) {
66                (CellId::NormalCell(s), CellId::NormalCell(e)) => {
67                    let range = Range::Normal(NormalRange::AddrRange(s, e));
68                    let range_id = id_fetcher.fetch_range_id(&curr_sheet, &range);
69                    Ok(ast::CellReference::Mut(RangeDisplay {
70                        range_id,
71                        ref_abs,
72                        sheet_id,
73                    }))
74                }
75                (CellId::BlockCell(s), CellId::BlockCell(e)) => {
76                    if s.block_id != e.block_id {
77                        panic!("")
78                    }
79
80                    let range = Range::Block(BlockRange::AddrRange(s, e));
81                    let range_id = id_fetcher.fetch_range_id(&curr_sheet, &range);
82                    Ok(ast::CellReference::Mut(RangeDisplay {
83                        range_id,
84                        ref_abs,
85                        sheet_id,
86                    }))
87                }
88                _ => panic!(),
89            }
90        };
91    match first.as_rule() {
92        Rule::work_sheet_prefix => {
93            let prefix = build_work_sheet_prefix(first);
94            let second = iter.next().unwrap();
95            match prefix {
96                Some(p) => {
97                    let unmut_prefix = build_unmut_prefix(&p, id_fetcher);
98                    match unmut_prefix {
99                        Some(prefix) => {
100                            let unmut = build_unmut_a1_reference_range(second);
101                            let ref_abs = RefAbs::from_addr_range(
102                                unmut.start.row_abs,
103                                unmut.end.row_abs,
104                                unmut.start.col_abs,
105                                unmut.end.col_abs,
106                            );
107                            let cross = CubeCross::AddrRange(
108                                Addr {
109                                    row: unmut.start.row,
110                                    col: unmut.start.col,
111                                },
112                                Addr {
113                                    row: unmut.end.row,
114                                    col: unmut.end.col,
115                                },
116                            );
117                            match prefix {
118                                ast::UnMutRefPrefix::Local(sts) => {
119                                    let cube = Cube {
120                                        from_sheet: sts.from_sheet,
121                                        to_sheet: sts.to_sheet,
122                                        cross,
123                                    };
124                                    let cube_id = id_fetcher.fetch_cube_id(&cube);
125                                    Ok(ast::CellReference::UnMut(CubeDisplay { cube_id, ref_abs }))
126                                }
127                                ast::UnMutRefPrefix::External(ext_prefix) => {
128                                    let ext_ref = ExtRef {
129                                        ext_book: ext_prefix.workbook,
130                                        from_sheet: ext_prefix.from_sheet,
131                                        to_sheet: ext_prefix.to_sheet,
132                                        cross,
133                                    };
134                                    let ext_ref_id = id_fetcher.fetch_ext_ref_id(&ext_ref);
135                                    Ok(ast::CellReference::Ext(ExtRefDisplay {
136                                        ext_ref_id,
137                                        ref_abs,
138                                    }))
139                                }
140                            }
141                        }
142                        None => {
143                            let sheet_id = id_fetcher.fetch_sheet_id(&p.sheet);
144                            build_mut_ref_range(second, sheet_id, id_fetcher)
145                        }
146                    }
147                }
148                None => build_mut_ref_range(second, curr_sheet, id_fetcher),
149            }
150        }
151        Rule::a1_reference_range => build_mut_ref_range(first, curr_sheet, id_fetcher),
152        _ => unreachable!(),
153    }
154}
155
156fn build_a1_reference_with_prefix<T>(
157    pair: Pair<Rule>,
158    curr_sheet: SheetId,
159    id_fetcher: &mut T,
160) -> Result<ast::CellReference>
161where
162    T: ContextTrait,
163{
164    let mut p_iter = pair.into_inner();
165    let first = p_iter.next().unwrap();
166    let build_mut_ref = |pair: Pair<Rule>,
167                         sheet_id: SheetId,
168                         id_fetcher: &mut T|
169     -> Result<ast::CellReference> {
170        let a1_ref = build_mut_a1_reference(pair, sheet_id, id_fetcher)?;
171        let range_display = match a1_ref {
172            ast::A1Reference::A1ColumnRange(col_range) => {
173                let ref_abs = RefAbs {
174                    start_row: false,
175                    start_col: col_range.start_abs,
176                    end_row: false,
177                    end_col: col_range.end_abs,
178                };
179                let range = Range::Normal(NormalRange::ColRange(col_range.start, col_range.end));
180                let range_id = id_fetcher.fetch_range_id(&sheet_id, &range);
181                RangeDisplay {
182                    range_id,
183                    ref_abs,
184                    sheet_id,
185                }
186            }
187            ast::A1Reference::A1RowRange(row_range) => {
188                let ref_abs = RefAbs {
189                    start_row: row_range.start_abs,
190                    start_col: false,
191                    end_row: row_range.end_abs,
192                    end_col: false,
193                };
194                let range = Range::Normal(NormalRange::RowRange(row_range.start, row_range.end));
195                let range_id = id_fetcher.fetch_range_id(&sheet_id, &range);
196                RangeDisplay {
197                    range_id,
198                    ref_abs,
199                    sheet_id,
200                }
201            }
202            ast::A1Reference::Addr(addr_range) => {
203                let ref_abs = RefAbs {
204                    start_row: addr_range.row_abs,
205                    start_col: addr_range.col_abs,
206                    end_row: false,
207                    end_col: false,
208                };
209                let range = match addr_range.cell_id {
210                    CellId::NormalCell(cell_id) => Range::Normal(NormalRange::Single(cell_id)),
211                    CellId::BlockCell(block_cell_id) => {
212                        Range::Block(BlockRange::Single(block_cell_id))
213                    }
214                };
215                let range_id = id_fetcher.fetch_range_id(&sheet_id, &range);
216                RangeDisplay {
217                    range_id,
218                    ref_abs,
219                    sheet_id,
220                }
221            }
222        };
223        Ok(ast::CellReference::Mut(range_display))
224    };
225    match first.as_rule() {
226        Rule::work_sheet_prefix => {
227            let prefix = build_work_sheet_prefix(first);
228            let second = p_iter.next().unwrap();
229            match prefix {
230                None => build_mut_ref(second, curr_sheet, id_fetcher),
231                Some(p) => {
232                    let unmut_prefix = build_unmut_prefix(&p, id_fetcher);
233                    match unmut_prefix {
234                        Some(prefix) => {
235                            let unmut = build_unmut_a1_reference(second);
236                            match (prefix, unmut) {
237                                (
238                                    ast::UnMutRefPrefix::Local(sts),
239                                    ast::UnMutA1Reference::A1ColumnRange(col_range),
240                                ) => {
241                                    let cube = Cube {
242                                        from_sheet: sts.from_sheet,
243                                        to_sheet: sts.to_sheet,
244                                        cross: CubeCross::ColRange(col_range.start, col_range.end),
245                                    };
246                                    let ref_abs = RefAbs::from_col_range(
247                                        col_range.start_abs,
248                                        col_range.end_abs,
249                                    );
250                                    let cube_id = id_fetcher.fetch_cube_id(&cube);
251                                    Ok(ast::CellReference::UnMut(CubeDisplay { cube_id, ref_abs }))
252                                }
253                                (
254                                    ast::UnMutRefPrefix::Local(sts),
255                                    ast::UnMutA1Reference::A1RowRange(row_range),
256                                ) => {
257                                    let cube = Cube {
258                                        from_sheet: sts.from_sheet,
259                                        to_sheet: sts.to_sheet,
260                                        cross: CubeCross::RowRange(row_range.start, row_range.end),
261                                    };
262                                    let ref_abs = RefAbs::from_row_range(
263                                        row_range.start_abs,
264                                        row_range.end_abs,
265                                    );
266                                    let cube_id = id_fetcher.fetch_cube_id(&cube);
267                                    Ok(ast::CellReference::UnMut(CubeDisplay { cube_id, ref_abs }))
268                                }
269                                (
270                                    ast::UnMutRefPrefix::Local(sts),
271                                    ast::UnMutA1Reference::Addr(addr),
272                                ) => {
273                                    let cube = Cube {
274                                        from_sheet: sts.from_sheet,
275                                        to_sheet: sts.to_sheet,
276                                        cross: CubeCross::Single(addr.row, addr.col),
277                                    };
278                                    let ref_abs = RefAbs::from_addr(addr.row_abs, addr.col_abs);
279                                    let cube_id = id_fetcher.fetch_cube_id(&cube);
280                                    Ok(ast::CellReference::UnMut(CubeDisplay { cube_id, ref_abs }))
281                                }
282                                (
283                                    ast::UnMutRefPrefix::External(ext_prefix),
284                                    ast::UnMutA1Reference::A1ColumnRange(col_range),
285                                ) => {
286                                    let cross = CubeCross::ColRange(col_range.start, col_range.end);
287                                    let ref_abs = RefAbs::from_col_range(
288                                        col_range.start_abs,
289                                        col_range.end_abs,
290                                    );
291                                    let ext_ref = ExtRef {
292                                        ext_book: ext_prefix.workbook,
293                                        from_sheet: ext_prefix.from_sheet,
294                                        to_sheet: ext_prefix.to_sheet,
295                                        cross,
296                                    };
297                                    let ext_ref_id = id_fetcher.fetch_ext_ref_id(&ext_ref);
298                                    Ok(ast::CellReference::Ext(ExtRefDisplay {
299                                        ext_ref_id,
300                                        ref_abs,
301                                    }))
302                                }
303                                (
304                                    ast::UnMutRefPrefix::External(ext_prefix),
305                                    ast::UnMutA1Reference::A1RowRange(row_range),
306                                ) => {
307                                    let cross = CubeCross::RowRange(row_range.start, row_range.end);
308                                    let ref_abs = RefAbs::from_row_range(
309                                        row_range.start_abs,
310                                        row_range.end_abs,
311                                    );
312                                    let ext_ref = ExtRef {
313                                        ext_book: ext_prefix.workbook,
314                                        from_sheet: ext_prefix.from_sheet,
315                                        to_sheet: ext_prefix.to_sheet,
316                                        cross,
317                                    };
318                                    let ext_ref_id = id_fetcher.fetch_ext_ref_id(&ext_ref);
319                                    Ok(ast::CellReference::Ext(ExtRefDisplay {
320                                        ext_ref_id,
321                                        ref_abs,
322                                    }))
323                                }
324                                (
325                                    ast::UnMutRefPrefix::External(ext_prefix),
326                                    ast::UnMutA1Reference::Addr(addr),
327                                ) => {
328                                    let cross = CubeCross::ColRange(addr.row, addr.col);
329                                    let ref_abs = RefAbs::from_addr(addr.row_abs, addr.col_abs);
330                                    let ext_ref = ExtRef {
331                                        ext_book: ext_prefix.workbook,
332                                        from_sheet: ext_prefix.from_sheet,
333                                        to_sheet: ext_prefix.to_sheet,
334                                        cross,
335                                    };
336                                    let ext_ref_id = id_fetcher.fetch_ext_ref_id(&ext_ref);
337                                    Ok(ast::CellReference::Ext(ExtRefDisplay {
338                                        ext_ref_id,
339                                        ref_abs,
340                                    }))
341                                }
342                            }
343                        }
344                        None => {
345                            let sheet_id = id_fetcher.fetch_sheet_id(&p.sheet);
346                            build_mut_ref(second, sheet_id, id_fetcher)
347                        }
348                    }
349                }
350            }
351        }
352        Rule::a1_reference => build_mut_ref(first, curr_sheet, id_fetcher),
353        _ => unreachable!(),
354    }
355}
356
357fn build_unmut_prefix<T>(
358    prefix: &ReferencePrefix,
359    id_fetcher: &mut T,
360) -> Option<ast::UnMutRefPrefix>
361where
362    T: ContextTrait,
363{
364    match (&prefix.workbook, &prefix.from_sheet) {
365        (None, None) => None,
366        (None, Some(from_sheet)) => {
367            let from_id = id_fetcher.fetch_sheet_id(&from_sheet);
368            let to_id = id_fetcher.fetch_sheet_id(&prefix.sheet);
369            Some(ast::UnMutRefPrefix::Local(ast::LocalSheetToSheet {
370                from_sheet: from_id,
371                to_sheet: to_id,
372            }))
373        }
374        (Some(workbook), None) => {
375            if id_fetcher.get_book_name() == workbook {
376                None
377            } else {
378                let ext_book_id = id_fetcher.fetch_ext_book_id(workbook);
379                Some(ast::UnMutRefPrefix::External(ast::ExternalPrefix {
380                    workbook: ext_book_id,
381                    from_sheet: None,
382                    to_sheet: id_fetcher.fetch_sheet_id(&prefix.sheet),
383                }))
384            }
385        }
386        (Some(workbook), Some(from_sheet)) => {
387            if id_fetcher.get_book_name() == workbook {
388                let from_id = id_fetcher.fetch_sheet_id(&from_sheet);
389                let to_id = id_fetcher.fetch_sheet_id(&prefix.sheet);
390                Some(ast::UnMutRefPrefix::Local(ast::LocalSheetToSheet {
391                    from_sheet: from_id,
392                    to_sheet: to_id,
393                }))
394            } else {
395                let from_id = id_fetcher.fetch_sheet_id(&from_sheet);
396                let to_id = id_fetcher.fetch_sheet_id(&prefix.sheet);
397                let ext_book_id = id_fetcher.fetch_ext_book_id(workbook);
398                Some(ast::UnMutRefPrefix::External(ast::ExternalPrefix {
399                    workbook: ext_book_id,
400                    from_sheet: Some(from_id),
401                    to_sheet: to_id,
402                }))
403            }
404        }
405    }
406}
407
408fn build_unmut_a1_reference_range(pair: Pair<Rule>) -> ast::UnMutA1ReferenceRange {
409    let mut iter = pair.into_inner();
410    let first = iter.next().unwrap();
411    let start = build_unmut_a1_reference(first);
412    let second = iter.next().unwrap();
413    let end = build_unmut_a1_reference(second);
414    match (start, end) {
415        (ast::UnMutA1Reference::Addr(s), ast::UnMutA1Reference::Addr(e)) => {
416            ast::UnMutA1ReferenceRange { start: s, end: e }
417        }
418        _ => unreachable!(),
419    }
420}
421
422fn build_mut_a1_reference_range<T>(
423    pair: Pair<Rule>,
424    sheet_id: SheetId,
425    id_fetcher: &mut T,
426) -> Result<ast::A1ReferenceRange>
427where
428    T: ContextTrait,
429{
430    let mut iter = pair.into_inner();
431    let first = iter.next().unwrap();
432    let start = build_mut_a1_addr(first, sheet_id, id_fetcher)?;
433    let second = iter.next().unwrap();
434    let end = build_mut_a1_addr(second, sheet_id, id_fetcher)?;
435    Ok(ast::A1ReferenceRange { start, end })
436}
437
438fn build_mut_a1_reference<T>(
439    pair: Pair<Rule>,
440    sheet_id: SheetId,
441    id_fetcher: &mut T,
442) -> Result<ast::A1Reference>
443where
444    T: IdFetcherTrait,
445{
446    let first = pair.into_inner().next().unwrap();
447    match first.as_rule() {
448        Rule::a1_addr => {
449            let addr = build_mut_a1_addr(first, sheet_id, id_fetcher)?;
450            Ok(ast::A1Reference::Addr(addr))
451        }
452        Rule::a1_column_range => {
453            let cr = build_mut_a1_column_range(first, sheet_id, id_fetcher)?;
454            Ok(ast::A1Reference::A1ColumnRange(cr))
455        }
456        Rule::a1_row_range => {
457            let rr = build_mut_a1_row_range(first, sheet_id, id_fetcher)?;
458            Ok(ast::A1Reference::A1RowRange(rr))
459        }
460        _ => unreachable!(),
461    }
462}
463
464fn build_unmut_a1_reference(pair: Pair<Rule>) -> ast::UnMutA1Reference {
465    let first = pair.into_inner().next().unwrap();
466    match first.as_rule() {
467        Rule::a1_addr => {
468            let addr = build_unmut_a1_addr(first);
469            ast::UnMutA1Reference::Addr(addr)
470        }
471        Rule::a1_column_range => {
472            let cr = build_unmut_a1_column_range(first);
473            ast::UnMutA1Reference::A1ColumnRange(cr)
474        }
475        Rule::a1_row_range => {
476            let rr = build_unmut_a1_row_range(first);
477            ast::UnMutA1Reference::A1RowRange(rr)
478        }
479        _ => unreachable!(),
480    }
481}
482
483fn build_mut_a1_addr<T>(
484    pair: Pair<Rule>,
485    sheet_id: SheetId,
486    id_fetcher: &mut T,
487) -> Result<ast::Address>
488where
489    T: IdFetcherTrait,
490{
491    let mut iter = pair.into_inner();
492    let column_pair = iter.next().unwrap();
493    let row_pair = iter.next().unwrap();
494    let (col_abs, col) = build_column(column_pair).unwrap_or((false, 1));
495    let (row_abs, row) = build_row(row_pair).unwrap_or((false, 1));
496    let cell_id = id_fetcher.fetch_cell_id(&sheet_id, row, col)?;
497    Ok(ast::Address {
498        cell_id,
499        row_abs,
500        col_abs,
501    })
502}
503
504fn build_unmut_a1_addr(pair: Pair<Rule>) -> ast::UnMutAddress {
505    let mut iter = pair.into_inner();
506    let column_pair = iter.next().unwrap();
507    let row_pair = iter.next().unwrap();
508    let (col_abs, col) = build_column(column_pair).unwrap_or((false, 1));
509    let (row_abs, row) = build_row(row_pair).unwrap_or((false, 1));
510    ast::UnMutAddress {
511        row,
512        col,
513        row_abs,
514        col_abs,
515    }
516}
517
518fn build_unmut_a1_column_range(pair: Pair<Rule>) -> ast::UnMutColRange {
519    let mut iter = pair.into_inner();
520    let first = iter.next().unwrap();
521    let (start_abs, start) = build_column(first).unwrap_or((false, 1));
522    let second = iter.next().unwrap();
523    let (end_abs, end) = build_column(second).unwrap_or((false, 1));
524    ast::UnMutColRange {
525        start,
526        start_abs,
527        end_abs,
528        end,
529    }
530}
531
532fn build_unmut_a1_row_range(pair: Pair<Rule>) -> ast::UnMutRowRange {
533    let mut iter = pair.into_inner();
534    let first = iter.next().unwrap();
535    let (start_abs, start) = build_row(first).unwrap_or((false, 1));
536    let second = iter.next().unwrap();
537    let (end_abs, end) = build_row(second).unwrap_or((false, 1));
538    ast::UnMutRowRange {
539        start_abs,
540        start,
541        end_abs,
542        end,
543    }
544}
545
546fn build_mut_a1_column_range<T>(
547    pair: Pair<Rule>,
548    sheet_id: SheetId,
549    id_fetcher: &mut T,
550) -> Result<ast::ColRange>
551where
552    T: IdFetcherTrait,
553{
554    let mut iter = pair.into_inner();
555    let first = iter.next().unwrap();
556    let (start_abs, start) = build_column(first).unwrap_or((false, 1));
557    let second = iter.next().unwrap();
558    let (end_abs, end) = build_column(second).unwrap_or((false, 1));
559    let start_id = id_fetcher.fetch_col_id(&sheet_id, start)?;
560    let end_id = id_fetcher.fetch_col_id(&sheet_id, end)?;
561    Ok(ast::ColRange {
562        start: start_id,
563        start_abs,
564        end_abs,
565        end: end_id,
566    })
567}
568
569fn build_mut_a1_row_range<T>(
570    pair: Pair<Rule>,
571    sheet_id: SheetId,
572    id_fetcher: &mut T,
573) -> Result<ast::RowRange>
574where
575    T: IdFetcherTrait,
576{
577    let mut iter = pair.into_inner();
578    let first = iter.next().unwrap();
579    let (start_abs, start) = build_row(first).unwrap_or((false, 1));
580    let second = iter.next().unwrap();
581    let (end_abs, end) = build_row(second).unwrap_or((false, 1));
582    let start_id = id_fetcher.fetch_row_id(&sheet_id, start)?;
583    let end_id = id_fetcher.fetch_row_id(&sheet_id, end)?;
584    Ok(ast::RowRange {
585        start: start_id,
586        end: end_id,
587        end_abs,
588        start_abs,
589    })
590}
591
592fn build_column(pair: Pair<Rule>) -> Result<(bool, usize)> {
593    parse_column(pair.as_str())
594}
595
596fn build_row(pair: Pair<Rule>) -> Result<(bool, usize)> {
597    parse_row(pair.as_str())
598}
599
600fn parse_row(row: &str) -> Result<(bool, usize)> {
601    let result = ROW_REGEX.captures_iter(row).next().map_or(
602        Err(ParseError::ParseRowFailed(row.to_string())),
603        |c| {
604            let abs = c.get(1).is_some();
605            let label = c
606                .get(2)
607                .ok_or(ParseError::ParseRowFailed(row.to_string()))?
608                .as_str();
609            let idx = label
610                .parse::<usize>()
611                .or(Err(ParseError::ParseRowFailed(row.to_string())))?
612                - 1;
613            Ok((abs, idx))
614        },
615    )?;
616    Ok(result)
617}
618
619fn parse_column(col: &str) -> Result<(bool, usize)> {
620    let result = COLUMN_REGEX.captures_iter(col).next().map_or(
621        Err(ParseError::ParseColFailed(col.to_string())),
622        |c| {
623            let abs = c.get(1).is_some();
624            let label = c
625                .get(2)
626                .ok_or(ParseError::ParseColFailed(col.to_string()))?
627                .as_str();
628            let i = column_label_to_index(label);
629            Ok((abs, i))
630        },
631    )?;
632    Ok(result)
633}
634
635#[derive(Debug, Clone, PartialEq, Eq)]
636pub struct ReferencePrefix {
637    pub sheet: String,
638    pub from_sheet: Option<String>,
639    pub workbook: Option<String>,
640}
641
642fn build_work_sheet_prefix(pair: Pair<Rule>) -> Option<ReferencePrefix> {
643    WORKSHEET_PREIFX_REGEX
644        .captures_iter(pair.as_str())
645        .next()
646        .map_or(None, |c| {
647            let sheet = c.get(5).map_or(None, |m| {
648                let name = m.as_str();
649                Some(name.to_string())
650            })?;
651            let workbook = c.get(2).map_or(None, |m| {
652                let name = m.as_str();
653                Some(name.to_string())
654            });
655            let from_sheet = c.get(4).map_or(None, |m| {
656                let name = m.as_str();
657                Some(name.to_string())
658            });
659            Some(ReferencePrefix {
660                sheet,
661                workbook,
662                from_sheet,
663            })
664        })
665}
666
667#[cfg(test)]
668mod tests {
669    use super::parse_column;
670    #[test]
671    fn parse_column_test() {
672        let col = "B";
673        let result = parse_column(col);
674        assert!(matches!(result, Ok((false, 1))));
675        let col = "$AB";
676        let result = parse_column(col);
677        assert!(matches!(result, Ok((true, 27))));
678    }
679}