-
Notifications
You must be signed in to change notification settings - Fork 8
/
errors.oc
176 lines (152 loc) · 4.55 KB
/
errors.oc
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
//* Utilities for displaying errors
import std::vector::Vector
import std::span::Span
import std::mem
import std::fs
enum ErrorType {
Standard
WithNote
WithHint
}
def ErrorType::str(this): str => match this {
Standard => "Standard"
WithNote => "WithNote"
WithHint => "WithHint"
}
struct Error {
type: ErrorType
msg1: str
span1: Span
msg2: str
span2: Span
}
enum MessageType {
Error
Warning
Note
}
def MessageType::to_color(this): str => match this {
Error => "\x1b[31m"
Warning => "\x1b[33m"
Note => "\x1b[32m"
}
def MessageType::str(this): str => match this {
Error => "Error"
Warning => "Warning"
Note => "Note"
}
def display_line() {
println("--------------------------------------------------------------------------------")
}
def display_message(type: MessageType, span: Span, msg: str) {
display_line()
let filename = span.start.filename
if filename == "<default>" or span.start.line == 0 {
println("%s: %s", type.str(), msg)
} else {
println("%s: %s: %s", span.start.str(), type.str(), msg)
}
display_line()
}
def display_message_span(type: MessageType, span: Span, msg: str, line_after: bool = true) {
let color = MessageType::to_color(type)
let reset = "\x1b[0m"
display_message(type, span, msg)
let filename = span.start.filename;
if not fs::file_exists(filename) return
let contents = fs::read_file(filename)
defer contents.free()
let around_offset = 1
let min_line = (span.start.line - around_offset).max(1)
let max_line = span.end.line + around_offset
max_line = max_line.min(min_line + 10) // Don't print more than 10 lines
// TODO: Use SVs here instead of strsep
let line_no = 1
for line in contents.sv().lines() {
if line_no > max_line break
if line_no >= min_line {
print(f"{line_no:4d} | ")
if line_no == span.start.line {
let start_col = span.start.col - 1
let end_col = span.end.col - 1
if span.end.line != span.start.line {
end_col = line.len
}
for let i = 0; i < start_col; i += 1 {
print(f"{line[i]}")
}
print(f"{color}")
for let i = start_col; i < end_col; i += 1 {
print(f"{line[i]}")
}
let remaining_line = line.slice(end_col)
println(f"{reset}{remaining_line}")
println("%*s%s^ %s%s", start_col + 7, "", color, msg, reset)
} else {
println(f"{line}")
}
}
line_no += 1
}
if line_after {
display_line()
}
}
def Error::display(&this) {
match .type {
Standard => {
display_message_span(MessageType::Error, .span1, .msg1)
}
WithNote => {
display_message_span(MessageType::Error, .span1, .msg1, line_after: false)
display_message(MessageType::Note, .span1, .msg2)
}
WithHint => {
display_message_span(MessageType::Error, .span1, .msg1, line_after: false)
display_message_span(MessageType::Note, .span2, .msg2)
}
}
}
[exits]
def Error::panic(&this) {
.display()
std::exit(1)
}
def Error::new(span: Span, msg: str): &Error {
let err = mem::alloc<Error>()
err.type = ErrorType::Standard
err.msg1 = msg
err.span1 = span
return err
}
def Error::new_note(span: Span, msg: str, note: str): &Error {
let err = mem::alloc<Error>()
err.type = ErrorType::WithNote
err.msg1 = msg
err.span1 = span
err.msg2 = note
return err
}
def Error::new_hint(span: Span, msg: str, span2: Span, hint: str): &Error {
let err = mem::alloc<Error>()
err.type = ErrorType::WithHint
err.msg1 = msg
err.span1 = span
err.msg2 = hint
err.span2 = span2
return err
}
def display_error_messages(errors: &Vector<&Error>, detail_level: u32) {
let num_errors_env = std::libc::getenv("OCEN_NUM_ERRORS")
let max_num_errors = if num_errors_env? then num_errors_env.to_u32() else 10
let num_errors = errors.size.min(max_num_errors)
for let i = 0; i < num_errors; i += 1 {
let err = errors.at(num_errors - i - 1)
match detail_level {
0 => println("%s: %s", err.span1.start.str(), err.msg1)
1 => display_message_span(MessageType::Error, err.span1, err.msg1)
2 => err.display()
else => std::panic("invalid detail level")
}
}
}