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}