1 /** 
2  * Copyright: Enalye
3  * License: Zlib
4  * Authors: Enalye
5  */
6 module grimoire.compiler.error;
7 
8 /// Contains a lot of information about what just happened.
9 final class GrError {
10     /// From which step the error come from.
11     enum Type {
12         lexer,
13         parser
14     }
15 
16     package {
17         Type _type;
18         string _message;
19         string _info;
20         string _note;
21         string _filePath;
22         size_t _line, _column;
23         size_t _textLength;
24         string _lineText;
25         string _otherInfo;
26         string _otherFilePath;
27         size_t _otherLine, _otherColumn;
28         size_t _otherTextLength;
29         string _otherLineText;
30     }
31 
32     @property {
33         /// From which step the error come from.
34         package Type type(Type type_) {
35             return _type = type_;
36         }
37         /// Ditto
38         Type type() const {
39             return _type;
40         }
41 
42         /// Error title.
43         package string message(string message_) {
44             return _message = message_;
45         }
46         /// Ditto
47         string message() const {
48             return _message;
49         }
50 
51         /// What's wrong in details.
52         package string info(string info_) {
53             return _info = info_;
54         }
55         /// Ditto
56         string info() const {
57             return _info;
58         }
59 
60         /// Some remarks about the problem.
61         package string note(string note_) {
62             return _note = note_;
63         }
64         /// Ditto
65         string note() const {
66             return _note;
67         }
68 
69         /// Script that generated the error.
70         package string filePath(string filePath_) {
71             return _filePath = filePath_;
72         }
73         /// Ditto
74         string filePath() const {
75             return _filePath;
76         }
77 
78         /// Line of the error inside the script.
79         package size_t line(size_t line_) {
80             return _line = line_;
81         }
82         /// Ditto
83         size_t line() const {
84             return _line;
85         }
86 
87         /// Character offset of the error at the line.
88         package size_t column(size_t column_) {
89             return _column = column_;
90         }
91         /// Ditto
92         size_t column() const {
93             return _column;
94         }
95 
96         /// Size of the error segment, the error is in between `column` and `column + textLength`
97         package size_t textLength(size_t textLength_) {
98             return _textLength = textLength_;
99         }
100         /// Ditto
101         size_t textLength() const {
102             return _textLength;
103         }
104 
105         /// The line from which the error originate
106         package string lineText(string lineText_) {
107             return _lineText = lineText_;
108         }
109         /// Ditto
110         string lineText() const {
111             return _lineText;
112         }
113 
114         /// What's wrong in details.
115         package string otherInfo(string otherInfo_) {
116             return _otherInfo = otherInfo_;
117         }
118         /// Ditto
119         string otherInfo() const {
120             return _otherInfo;
121         }
122 
123         /// Script that generated the error.
124         package string otherFilePath(string otherFilePath_) {
125             return _otherFilePath = otherFilePath_;
126         }
127         /// Ditto
128         string otherFilePath() const {
129             return _otherFilePath;
130         }
131 
132         /// Line of the error inside the script.
133         package size_t otherLine(size_t otherLine_) {
134             return _otherLine = otherLine_;
135         }
136         /// Ditto
137         size_t otherLine() const {
138             return _otherLine;
139         }
140 
141         /// Character offset of the error at the line.
142         package size_t otherColumn(size_t otherColumn_) {
143             return _otherColumn = otherColumn_;
144         }
145         /// Ditto
146         size_t otherColumn() const {
147             return _otherColumn;
148         }
149 
150         /// Size of the error segment, the error is in between `column` and `column + textLength`
151         package size_t otherTextLength(size_t otherTextLength_) {
152             return _otherTextLength = otherTextLength_;
153         }
154         /// Ditto
155         size_t otherTextLength() const {
156             return _otherTextLength;
157         }
158 
159         /// The line from which the error originate
160         package string otherLineText(string otherLineText_) {
161             return _otherLineText = otherLineText_;
162         }
163         /// Ditto
164         string otherLineText() const {
165             return _otherLineText;
166         }
167     }
168 
169     /// Format the error and prints it.
170     string prettify() {
171         import std.conv : to;
172         import std.algorithm.comparison : clamp;
173 
174         string report, lineNumber;
175 
176         report ~= "\033[0;91merror";
177         //report ~= "\033[0;93mwarning";
178 
179         //Error report
180         report ~= "\033[37;1m: " ~ _message ~ "\n";
181 
182         //Additional info
183         if (_otherInfo.length) {
184             //Error report
185             report ~= "\033[37;0m";
186 
187             //File path
188             lineNumber = to!string(_otherLine) ~ "| ";
189             foreach (x; 1 .. lineNumber.length)
190                 report ~= " ";
191 
192             report ~= "\033[1;34m->\033[0m " ~ _otherFilePath ~ "(" ~ to!string(
193                     _otherLine) ~ "," ~ to!string(_otherColumn) ~ ")\n";
194 
195             report ~= "\033[1;36m";
196 
197             foreach (x; 1 .. lineNumber.length)
198                 report ~= " ";
199             report ~= "\033[1;34m|\n";
200 
201             //Script snippet
202             report ~= " " ~ lineNumber;
203             report ~= "\033[1;34m" ~ _otherLineText ~ "\033[1;34m\n";
204 
205             //Red underline
206             foreach (x; 1 .. lineNumber.length)
207                 report ~= " ";
208             report ~= "\033[1;34m|";
209             foreach (x; 0 .. _otherColumn)
210                 report ~= " ";
211 
212             report ~= "\033[1;36m";
213 
214             foreach (x; 0 .. _otherTextLength)
215                 report ~= "-";
216 
217             //Error description
218             if (_otherInfo.length)
219                 report ~= "  " ~ _otherInfo;
220             report ~= "\n";
221         }
222 
223         //File path
224         lineNumber = to!string(_line) ~ "| ";
225         foreach (x; 1 .. lineNumber.length)
226             report ~= " ";
227 
228         report ~= "\033[1;34m->\033[0m " ~ _filePath ~ "(" ~ to!string(
229                 _line) ~ "," ~ to!string(_column) ~ ")\n";
230 
231         report ~= "\033[1;36m";
232 
233         foreach (x; 1 .. lineNumber.length)
234             report ~= " ";
235         report ~= "\033[1;34m|\n";
236 
237         //Script snippet
238         report ~= " " ~ lineNumber;
239         report ~= "\033[1;34m" ~ _lineText ~ "\033[1;34m\n";
240 
241         //Red underline
242         foreach (x; 1 .. lineNumber.length)
243             report ~= " ";
244         report ~= "\033[1;34m|";
245         foreach (x; 0 .. clamp(_column, 0, _lineText.length))
246             report ~= " ";
247 
248         report ~= "\033[1;31m"; //Red color
249         //report ~= "\033[1;93m"; //Orange color
250 
251         foreach (x; 0 .. _textLength)
252             report ~= "^";
253 
254         //Error description
255         report ~= "\033[1;31m"; //Red color
256         //report ~= "\033[0;93m"; //Orange color
257 
258         if (_info.length)
259             report ~= "  " ~ _info;
260 
261         if (note.length) {
262             report ~= "\n\033[1;36mnote\033[1;37m: " ~ _note ~ "\033[37;0m";
263         }
264         else {
265             report ~= "\033[37;0m";
266         }
267         return report;
268     }
269 }