1use rustlavel_core::Error;
8
9pub fn line_column(source: &str, offset: usize) -> (usize, usize) {
14 let offset = offset.min(source.len());
15 let consumed = &source.as_bytes()[..offset];
16 let line = consumed.iter().filter(|byte| **byte == b'\n').count() + 1;
17 let column =
18 consumed.iter().rposition(|byte| *byte == b'\n').map_or(offset, |i| offset - i - 1) + 1;
19 (line, column)
20}
21
22pub fn syntax_error(
24 file: &str,
25 source: &str,
26 offset: usize,
27 message: impl Into<String>,
28) -> Error {
29 let (line, column) = line_column(source, offset);
30 Error::Template { file: file.to_string(), line, column, message: message.into() }
31}
32
33#[derive(Debug, Clone, Copy)]
39pub struct Span<'a> {
40 pub file: &'a str,
42 pub source: &'a str,
44 pub offset: usize,
46 pub text: &'a str,
48}
49
50impl<'a> Span<'a> {
51 pub fn new(file: &'a str, source: &'a str, offset: usize, len: usize) -> Self {
52 Span { file, source, offset, text: &source[offset..offset + len] }
53 }
54
55 pub fn error(&self, at: usize, message: impl Into<String>) -> Error {
57 syntax_error(self.file, self.source, self.offset + at, message)
58 }
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64
65 #[test]
66 fn counts_lines_and_columns_from_one() {
67 let source = "hello\n world\n";
68
69 assert_eq!(line_column(source, 0), (1, 1));
70 assert_eq!(line_column(source, 4), (1, 5));
71 assert_eq!(line_column(source, 6), (2, 1));
72 assert_eq!(line_column(source, 8), (2, 3));
73 }
74
75 #[test]
76 fn an_offset_past_the_end_lands_on_the_last_position() {
77 assert_eq!(line_column("ab", 99), (1, 3));
78 }
79
80 #[test]
81 fn a_span_reports_positions_relative_to_its_fragment() {
82 let source = "line one\n@if(x == )\n";
83 let span = Span::new("home", source, 13, 5);
84
85 assert_eq!(span.text, "x == ");
86 match span.error(5, "unexpected end of expression") {
87 Error::Template { file, line, column, .. } => {
88 assert_eq!((file.as_str(), line, column), ("home", 2, 10));
89 }
90 other => panic!("expected a template error, got {other:?}"),
91 }
92 }
93}