1use super::*;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
4pub struct Token<'src> {
5 pub column: usize,
6 pub kind: TokenKind,
7 pub length: usize,
8 pub line: usize,
9 pub offset: usize,
10 pub path: &'src Path,
11 pub src: &'src str,
12}
13
14impl<'src> Token<'src> {
15 pub fn lexeme(&self) -> &'src str {
16 &self.src[self.offset..self.offset + self.length]
17 }
18
19 pub fn error(&self, kind: CompileErrorKind<'src>) -> CompileError<'src> {
20 CompileError::new(*self, kind)
21 }
22}
23
24impl<'src> ColorDisplay for Token<'src> {
25 fn fmt(&self, f: &mut Formatter, color: Color) -> fmt::Result {
26 let width = if self.length == 0 { 1 } else { self.length };
27
28 let line_number = self.line.ordinal();
29 match self.src.lines().nth(self.line) {
30 Some(line) => {
31 let mut i = 0;
32 let mut space_column = 0;
33 let mut space_line = String::new();
34 let mut space_width = 0;
35 for c in line.chars() {
36 if c == '\t' {
37 space_line.push_str(" ");
38 if i < self.column {
39 space_column += 4;
40 }
41 if i >= self.column && i < self.column + width {
42 space_width += 4;
43 }
44 } else {
45 if i < self.column {
46 space_column += UnicodeWidthChar::width(c).unwrap_or(0);
47 }
48 if i >= self.column && i < self.column + width {
49 space_width += UnicodeWidthChar::width(c).unwrap_or(0);
50 }
51 space_line.push(c);
52 }
53 i += c.len_utf8();
54 }
55 let line_number_width = line_number.to_string().len();
56 writeln!(
57 f,
58 "{:width$}{} {}:{}:{}",
59 "",
60 color.context().paint("——▶"),
61 self.path.display(),
62 line_number,
63 self.column.ordinal(),
64 width = line_number_width
65 )?;
66 writeln!(
67 f,
68 "{:width$} {}",
69 "",
70 color.context().paint("│"),
71 width = line_number_width
72 )?;
73 writeln!(
74 f,
75 "{} {space_line}",
76 color.context().paint(&format!("{line_number} │"))
77 )?;
78 write!(
79 f,
80 "{:width$} {}",
81 "",
82 color.context().paint("│"),
83 width = line_number_width
84 )?;
85 write!(
86 f,
87 " {0:1$}{2}{3:^<4$}{5}",
88 "",
89 space_column,
90 color.prefix(),
91 "",
92 space_width.max(1),
93 color.suffix()
94 )?;
95 }
96 None => {
97 if self.offset != self.src.len() {
98 write!(
99 f,
100 "internal error: Error has invalid line number: {line_number}"
101 )?;
102 }
103 }
104 }
105
106 Ok(())
107 }
108}