1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
use std::fmt;
use serde::{Deserialize, Serialize};
use crate::{formatting::source_lines, sources::Source};
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct Range {
pub start: Position,
pub end: Position,
}
impl Range {
pub fn from_span(source: &str, (left, right): (usize, usize)) -> Self {
let start = Position::from_loc(source, left);
let end = Position::from_loc(source, right);
Self { start, end }
}
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct Position {
pub row: usize,
pub column: usize,
}
impl Position {
pub fn from_loc(source: &str, loc: usize) -> Self {
let (row, column) = crate::lexer::loc_to_pos(source, loc);
Self { row, column }
}
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Context {
pub source: Source,
pub range: Range,
}
fn pos_to_loc(src: &str, row: usize, column: usize) -> usize {
let chars_before_row = src.split('\n').take(row).flat_map(|r| r.chars()).count();
row + chars_before_row + column
}
impl fmt::Display for Context {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let Position { row, column } = self.range.start;
write!(f, " at line {}, column {}", row + 1, column + 1)?;
if let Some(ref filename) = self.source.filename {
write!(f, " of file {}", filename)?;
}
let loc = pos_to_loc(&self.source.src, row, column);
let lines = source_lines(&self.source, loc, 0).replace('\n', "\n\t");
writeln!(f, ":\n\t{}", lines)?;
Ok(())
}
}