This repository has been archived by the owner on Apr 5, 2024. It is now read-only.
forked from ocen-lang/ocen
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patherrors.oc
175 lines (150 loc) · 4.52 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
//* Utilities for displaying errors
import std::vector::Vector
import std::span::Span
import std::libc::{free, strsep, exit, calloc, getenv as get_environment_variable}
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()
println("%s: %s: %s", span.start.str(), type.str(), msg)
display_line()
}
def display_message_span(type: MessageType, span: Span, msg: str) {
let color = MessageType::to_color(type)
let reset = "\x1b[0m"
display_message(type, span, msg)
let filename = span.start.filename;
if not std::File::exists(filename) return
let file = std::File::open(filename, "r")
defer file.close()
let contents = file.slurp()
defer free(contents)
let around_offset = 1
let min_line = (span.start.line - around_offset).max(1)
let max_line = span.end.line + around_offset
let lines = contents
let cur = strsep(&lines, "\n")
let line_no = 1
while cur? and line_no <= max_line {
if line_no >= min_line and line_no <= max_line {
print("%4d | ", line_no)
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 = cur.len()
}
for let i = 0; i < start_col; i += 1 {
print("%c", cur[i])
}
print("%s", color)
for let i = start_col; i < end_col; i += 1 {
print("%c", cur[i])
}
println("%s%s", reset, &cur[end_col])
println("%*s%s^ %s%s", start_col + 7, "", color, msg, reset)
} else {
println("%s", cur)
}
}
line_no += 1
cur = strsep(&lines, "\n")
}
}
def Error::display(&this) {
match .type {
Standard => {
display_message_span(MessageType::Error, .span1, .msg1)
display_line()
}
WithNote => {
display_message_span(MessageType::Error, .span1, .msg1)
display_message(MessageType::Note, .span1, .msg2)
}
WithHint => {
display_message_span(MessageType::Error, .span1, .msg1)
display_message_span(MessageType::Note, .span2, .msg2)
display_line()
}
}
}
def Error::panic(&this) exits {
.display()
exit(1)
}
def Error::new(span: Span, msg: str): &Error {
let err = calloc(1, sizeof(Error)) as &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 = calloc(1, sizeof(Error)) as &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 = calloc(1, sizeof(Error)) as &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 = get_environment_variable("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)
let first = true
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 => {
if first then println("")
first = false
err.display()
}
else => std::panic("invalid detail level")
}
}
}