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
use crate::Location;
use std::fmt::Display;
#[derive(Debug, PartialEq, Eq)]
pub struct BaseError<T> {
pub error: T,
pub location: Location,
pub source_path: String,
}
impl<T> std::ops::Deref for BaseError<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.error
}
}
impl<T> std::error::Error for BaseError<T> where T: std::fmt::Display + std::fmt::Debug {}
impl<T> Display for BaseError<T>
where
T: std::fmt::Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.location.fmt_with(f, &self.error)
}
}
impl<T> BaseError<T> {
pub fn error(self) -> T {
self.error
}
pub fn from<U>(obj: BaseError<U>) -> Self
where
U: Into<T>,
{
Self {
error: obj.error.into(),
location: obj.location,
source_path: obj.source_path,
}
}
pub fn into<U>(self) -> BaseError<U>
where
T: Into<U>,
{
BaseError::from(self)
}
}
#[derive(Debug, thiserror::Error)]
pub struct CompileError<T> {
pub body: BaseError<T>,
pub statement: Option<String>,
}
impl<T> std::ops::Deref for CompileError<T> {
type Target = BaseError<T>;
fn deref(&self) -> &Self::Target {
&self.body
}
}
impl<T> std::fmt::Display for CompileError<T>
where
T: std::fmt::Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let loc = self.location;
if let Some(ref stmt) = self.statement {
loc.fmt_with(f, &self.error)?;
write!(f, "\n{stmt}{arrow:>pad$}", pad = loc.column(), arrow = "^")
} else {
loc.fmt_with(f, &self.error)
}
}
}
impl<T> CompileError<T> {
pub fn from<U>(error: BaseError<U>, source: &str) -> Self
where
T: From<U>,
{
let statement = get_statement(source, error.location);
CompileError {
body: error.into(),
statement,
}
}
}
fn get_statement(source: &str, loc: Location) -> Option<String> {
if loc.column() == 0 || loc.row() == 0 {
return None;
}
let line = source.split('\n').nth(loc.row() - 1)?.to_owned();
Some(line + "\n")
}