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 }