surql_parser/upstream/syn/error/
location.rs1use crate::upstream::syn::token::Span;
2use std::ops::Range;
3#[derive(Clone, Copy, Debug)]
8pub struct Location {
9 pub line: usize,
10 pub column: usize,
12}
13unsafe fn str_offset(a: &str, b: &str) -> usize {
15 unsafe { b.as_ptr().offset_from(a.as_ptr()) as usize }
16}
17impl Location {
18 fn range_of_source_end(source: &str) -> Range<Self> {
19 let (line, column) = source
20 .lines()
21 .enumerate()
22 .last()
23 .map(|(idx, line)| {
24 let idx = idx + 1;
25 let line_idx = line.chars().count().max(1);
26 (idx, line_idx)
27 })
28 .unwrap_or((1, 1));
29 Self { line, column }..Self {
30 line,
31 column: column + 1,
32 }
33 }
34 pub fn range_of_span(source: &str, span: Span) -> Range<Self> {
35 if source.len() <= span.offset as usize {
36 return Self::range_of_source_end(source);
37 }
38 let mut prev_line = "";
39 let mut lines = source.lines().enumerate().peekable();
40 let start_offset = span.offset as usize;
41 let start = loop {
42 let Some((line_idx, line)) = lines.peek().copied() else {
43 return Self::range_of_source_end(source);
44 };
45 let line_offset = unsafe { str_offset(source, line) };
46 if start_offset < line_offset {
47 let len = prev_line.chars().count();
48 break Self {
49 line: line_idx,
50 column: len + 1,
51 };
52 }
53 if (line_offset..(line_offset + line.len())).contains(&start_offset) {
54 let column_offset = start_offset - line_offset;
55 let column = line
56 .char_indices()
57 .enumerate()
58 .find(|(_, (char_idx, _))| *char_idx >= column_offset)
59 .map(|(l, _)| l)
60 .unwrap_or_else(|| line.chars().count());
61 break Self {
62 line: line_idx + 1,
63 column: column + 1,
64 };
65 }
66 lines.next();
67 prev_line = line;
68 };
69 let end_offset = span.offset as usize + span.len as usize;
70 let end = loop {
71 let Some((line_idx, line)) = lines.peek().copied() else {
72 break Self::range_of_source_end(source).end;
73 };
74 let line_offset = unsafe { str_offset(source, line) };
75 if end_offset < line_offset {
76 let len = prev_line.chars().count();
77 break Self {
78 line: line_idx,
79 column: len + 1,
80 };
81 }
82 if (line_offset..(line_offset + line.len())).contains(&end_offset) {
83 let column_offset = end_offset - line_offset;
84 let column = line
85 .char_indices()
86 .enumerate()
87 .find(|(_, (char_idx, _))| *char_idx >= column_offset)
88 .map(|(l, _)| l)
89 .unwrap_or_else(|| line.chars().count());
90 break Self {
91 line: line_idx + 1,
92 column: column + 1,
93 };
94 }
95 lines.next();
96 prev_line = line;
97 };
98 start..end
99 }
100}