summaryrefslogtreecommitdiff
path: root/src/locators/source.rs
blob: 7e5abd2e86ce538726209c34ce237cef060bfeca (plain) (blame)
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
use std::path::PathBuf;


#[derive(Clone)]
pub struct SourceSpan {
    /// The source characters which this span represents.
    pub string: String,
    /// The location of this span in the merged source file.
    pub in_merged: SourceLocation,
    /// The location of this span in the original source file.
    pub in_source: Option<SourceLocation>,
    /// Drill down to a more accurate location.
    pub child: Option<Box<SourceSpan>>,
}

impl SourceSpan {
    pub fn location(&self) -> &SourceLocation {
        self.in_source.as_ref().unwrap_or(&self.in_merged)
    }

    /// Wrap this source span around a child source span.
    pub fn wrap(mut self, source: SourceSpan) -> Self {
        self.child = Some(Box::new(source)); self
    }
}


#[derive(Clone)]
pub struct SourceLocation {
    /// File path the source was loaded from.
    pub path: Option<PathBuf>,
    /// Position of the first character of the string.
    pub start: SourcePosition,
    /// Position of the final character of the string.
    pub end: SourcePosition,
}

impl std::fmt::Display for SourceLocation {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        let y = self.start.line + 1;
        let x = self.start.column + 1;
        match &self.path {
            Some(path) => write!(f, "{}:{y}:{x}", path.as_os_str().to_string_lossy()),
            None => write!(f, "<unknown>:{y}:{x}"),
        }
    }
}


#[derive(Clone, Copy)]
pub struct SourcePosition {
    /// The number of lines that precede this line in the source file.
    pub line: usize,
    /// The number of characters that precede this character in the line.
    pub column: usize,
}

impl SourcePosition {
    pub const ZERO: Self = Self { line: 0, column: 0 };

    // Advance to the next character in the row.
    pub fn to_next_char(&mut self) {
        self.column += 1;
    }

    // Advance to the start of the next line.
    pub fn to_next_line(&mut self) {
        self.line += 1;
        self.column = 0;
    }

    // Advance to the next character, wrapping on line breaks.
    pub fn advance(&mut self, c: char) {
        match c {
            '\n' => self.to_next_line(),
            _ => self.to_next_char(),
        }
    }
}

impl std::fmt::Display for SourcePosition {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        let y = self.line + 1;
        let x = self.column + 1;
        write!(f, "{y}:{x}")
    }
}