1 module source.location; 2 3 import source.context; 4 5 /** 6 * Struct representing a location in a source file. 7 * Effectively a pair of Position within the source file. 8 */ 9 struct Location { 10 package: 11 Position _start; 12 Position _stop; 13 14 public: 15 this(Position start, Position stop) in { 16 assert(start.isMixin() == stop.isMixin()); 17 assert(start.offset <= stop.offset); 18 } do { 19 this._start = start; 20 this._stop = stop; 21 } 22 23 @property 24 Position start() const { 25 return _start; 26 } 27 28 @property 29 Position stop() const { 30 return _stop; 31 } 32 33 @property 34 uint length() const { 35 return stop.offset - start.offset; 36 } 37 38 @property 39 bool isFile() const { 40 return start.isFile(); 41 } 42 43 @property 44 bool isMixin() const { 45 return start.isMixin(); 46 } 47 48 void spanTo(Location end) in { 49 import std.conv; 50 assert( 51 stop.offset <= end.stop.offset, 52 to!string(stop.offset) ~ " > " ~ to!string(end.stop.offset) 53 ); 54 } do { 55 spanTo(end.stop); 56 } 57 58 void spanTo(Position end) in { 59 import std.conv; 60 assert( 61 stop.offset <= end.offset, 62 to!string(stop.offset) ~ " > " ~ to!string(end.offset) 63 ); 64 } do { 65 _stop = end; 66 } 67 68 auto getFullLocation(Context c) const { 69 return FullLocation(this, c); 70 } 71 } 72 73 /** 74 * Struct representing a position in a source file. 75 */ 76 struct Position { 77 private: 78 import std.bitmanip; 79 mixin(bitfields!( 80 uint, "_offset", uint.sizeof * 8 - 1, 81 bool, "_mixin", 1, 82 )); 83 84 package: 85 @property 86 uint offset() const { 87 return _offset; 88 } 89 90 @property 91 uint raw() const { 92 return *(cast(uint*) &this); 93 } 94 95 bool isFile() const { 96 return !_mixin; 97 } 98 99 bool isMixin() const { 100 return _mixin; 101 } 102 103 public: 104 Position getWithOffset(uint offset) const out(result) { 105 assert(result.isMixin() == isMixin(), "Position overflow"); 106 } do { 107 return Position(raw + offset); 108 } 109 110 Location getWithOffsets(uint start, uint stop) { 111 return Location(getWithOffset(start), getWithOffset(stop)); 112 } 113 114 auto getFullPosition(Context c) const { 115 return FullPosition(this, c); 116 } 117 } 118 119 /** 120 * A Location associated with a context, so it can probe various infos. 121 */ 122 struct FullLocation { 123 private: 124 Location _location; 125 Context context; 126 127 @property 128 inout(FullPosition) start() inout { 129 return inout(FullPosition)(location.start, context); 130 } 131 132 @property 133 inout(FullPosition) stop() inout { 134 return inout(FullPosition)(location.stop, context); 135 } 136 137 @property 138 ref sourceManager() inout { 139 return context.sourceManager; 140 } 141 142 public: 143 this(Location location, Context context) { 144 this._location = location; 145 this.context = context; 146 147 import std.conv; 148 assert( 149 length == 0 || 150 start.getSource() == Position(stop.raw - 1).getFullPosition(context).getSource(), 151 /+ 152 "Location file mismatch " ~ 153 start.getFileName() ~ ":" ~ to!string(getStartOffset()) ~ " and " ~ 154 stop.getFileName() ~ ":" ~ to!string(getStopOffset()) 155 /* +/ /*/ /+ */ 156 "Location file mismatch" 157 // +/ 158 ); 159 } 160 161 alias location this; 162 @property location() const { 163 return _location; 164 } 165 166 auto getSource() out(result) { 167 assert(result.isMixin() == isMixin()); 168 } do { 169 return start.getSource(); 170 } 171 172 string getSlice() { 173 return getSource().getSlice(this); 174 } 175 176 uint getStartLineNumber() { 177 return start.getLineNumber(); 178 } 179 180 uint getStopLineNumber() { 181 return stop.getLineNumber(); 182 } 183 184 uint getStartColumn() { 185 return start.getColumn(); 186 } 187 188 uint getStopColumn() { 189 return stop.getColumn(); 190 } 191 192 uint getStartOffset() { 193 return start.getSourceOffset(); 194 } 195 196 uint getStopOffset() { 197 return stop.getSourceOffset(); 198 } 199 } 200 201 /** 202 * A Position associated with a context, so it can probe various infos. 203 */ 204 struct FullPosition { 205 private: 206 Position _position; 207 Context context; 208 209 @property 210 uint offset() const { 211 return position.offset; 212 } 213 214 @property 215 ref sourceManager() inout { 216 return context.sourceManager; 217 } 218 219 public: 220 alias position this; 221 @property position() const { 222 return _position; 223 } 224 225 auto getSource() out(result) { 226 assert(result.isMixin() == isMixin()); 227 } do { 228 return sourceManager.getFileID(this).getSource(context); 229 } 230 231 uint getLineNumber() { 232 return sourceManager.getLineNumber(this); 233 } 234 235 uint getColumn() { 236 return sourceManager.getColumn(this); 237 } 238 239 uint getSourceOffset() { 240 return getSource().getOffset(this); 241 } 242 }