1 /// Author: Aziz Köksal 2 /// License: GPL3 3 /// $(Maturity high) 4 module dil.Location; 5 6 import dil.lexer.Funcs; 7 import dil.Unicode; 8 import common; 9 10 /// Represents a location in a source text. 11 final class Location 12 { 13 cstring filePath; /// The file path. 14 size_t lineNum; /// The line number. 15 cchar* lineBegin, to; /// Used to calculate the column. 16 17 static uint TAB_WIDTH = 4; /// The default width of the tabulator character. 18 19 /// Forwards the parameters to the second constructor. 20 this(cstring filePath, size_t lineNum) 21 { 22 set(filePath, lineNum); 23 } 24 25 /// Constructs a Location object. 26 this(cstring filePath, size_t lineNum, cchar* lineBegin, cchar* to) 27 { 28 set(filePath, lineNum, lineBegin, to); 29 } 30 31 void set(cstring filePath, size_t lineNum) 32 { 33 set(filePath, lineNum, null, null); 34 } 35 36 void set(cstring filePath, size_t lineNum, cchar* lineBegin, cchar* to) 37 { 38 this.filePath = filePath; 39 set(lineNum, lineBegin, to); 40 } 41 42 void set(size_t lineNum, cchar* lineBegin, cchar* to) 43 { 44 assert(lineBegin <= to); 45 this.lineNum = lineNum; 46 this.lineBegin = lineBegin; 47 this.to = to; 48 } 49 50 void setFilePath(cstring filePath) 51 { 52 this.filePath = filePath; 53 } 54 55 /// Uses a simple method to count the number of characters in a string. 56 /// 57 /// Note: Unicode compound characters and other special characters are not 58 /// taken into account. 59 /// Params: 60 /// tabWidth = The width of the tabulator character. 61 uint calculateColumn(uint tabWidth = Location.TAB_WIDTH) 62 { 63 uint col; 64 auto p = lineBegin; 65 if (!p) 66 return 0; 67 for (; p <= to; p++) 68 { 69 assert(delegate () 70 { 71 // Check that there is no newline between p and to. 72 // But 'to' may point to a newline. 73 if (p != to && isNewline(*p)) 74 return false; 75 if (to-p >= 2 && isUnicodeNewline(p)) 76 return false; 77 return true; 78 }() == true 79 ); 80 81 // Skip this byte if it is a trail byte of a UTF-8 sequence. 82 if (isTrailByte(*p)) 83 continue; // *p == 0b10xx_xxxx 84 85 // Only count ASCII characters and the first byte of a UTF-8 sequence. 86 if (*p == '\t') 87 col += tabWidth; 88 else 89 col++; 90 } 91 return col; 92 } 93 alias colNum = calculateColumn; 94 95 char[] str(cstring format = "({},{})") 96 { 97 return Format(format, lineNum, colNum); 98 } 99 100 char[] repr(cstring format = "{}({},{})") 101 { 102 return Format(format, filePath, lineNum, colNum); 103 } 104 }