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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
use crate::{
interpret::walker::WalkerError,
lex::token::Location,
parse::parser::{ParserError, ParserErrorLocation},
};
use colored::Colorize;
use std::fmt::Display;
pub enum RHError {
Parse(ParserError),
Run(WalkerError),
}
impl RHError {
pub fn hydrate_source<'s>(self, source: &'s str) -> RHErrorWithSource<'s> {
RHErrorWithSource {
error: self,
source,
}
}
}
pub struct RHErrorWithSource<'source> {
error: RHError,
source: &'source str,
}
impl Display for RHErrorWithSource<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let (error_title, error_string) = match &self.error {
RHError::Parse(parser_error) => (
"Encountered error during parsing",
format!("{}", parser_error.kind),
),
RHError::Run(walker_error) => (
"Encountered runtime error",
format!("{}", walker_error.kind),
),
};
let at = MappedErrorLocation::new(self);
let arrow_pad_len = at.line_column + 3 + at.line_number.to_string().len();
writeln!(f, "{} {}:\n", " Error ".on_red(), error_title)?;
writeln!(
f,
"{}{}",
format!("{} | ", at.line_number).dimmed(),
at.source_line
)?;
writeln!(f, "{}{}", " ".repeat(arrow_pad_len), "^".red())?;
writeln!(f, "{}", error_string)?;
Ok(())
}
}
pub struct MappedErrorLocation<'s> {
line_number: usize,
line_column: usize,
source_line: &'s str,
}
impl<'s> MappedErrorLocation<'s> {
const SOURCE_MISSING_ERROR_LOCATION: &'static str =
"Found error but could not get it's location in source, how does this even happen?";
fn new(from: &'s RHErrorWithSource<'s>) -> MappedErrorLocation<'s> {
match &from.error {
RHError::Parse(error) => match &error.at {
ParserErrorLocation::Specific(at) => Self::at_location(from, at),
ParserErrorLocation::Eof => Self::last_line(from),
},
RHError::Run(error) => Self::at_location(from, &error.at),
}
}
fn last_line(from: &'s RHErrorWithSource<'s>) -> MappedErrorLocation<'s> {
let lines = from.source.lines();
let (line_count, _) = lines.size_hint();
let last_line = lines.last().expect(Self::SOURCE_MISSING_ERROR_LOCATION);
MappedErrorLocation {
line_number: line_count,
line_column: last_line.len(),
source_line: last_line,
}
}
fn at_location(
from: &'s RHErrorWithSource<'s>,
location: &'s Location,
) -> MappedErrorLocation<'s> {
MappedErrorLocation {
line_number: location.row,
line_column: location.col,
source_line: from
.source
.lines()
.nth(location.row)
.expect(Self::SOURCE_MISSING_ERROR_LOCATION),
}
}
}
|