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
|
package dotty.tools.dotc
package util
/** Position format in little endian:
* Start: unsigned 26 Bits (works for source files up to 64M)
* End: unsigned 26 Bits
* Point: unsigned 12 Bits relative to start
* NoPosition encoded as -1L (this is a normally invalid position
* because point would lie beyond end.
*/
object Positions {
private val StartEndBits = 26
private val StartEndMask: Long = (1L << StartEndBits) - 1
private val PointOffsetLimit = 1L << (64 - StartEndBits * 2)
class Position(val coords: Long) extends AnyVal {
def start: Int = (coords & StartEndMask).toInt
def point: Int = start + (coords >>> (StartEndBits * 2)).toInt
def end: Int = ((coords >>> StartEndBits) & StartEndMask).toInt
/** The union of two positions. Tries to keep the point offset of
* the first positon if within range. Otherwise, pointoffset will be 0.
*/
def union(that: Position) =
if (!this.exists) that
else if (!that.exists) this
else {
val start = this.start min that.start
val end = this.end max that.end
var pointOffset = this.point - start
if (pointOffset >= PointOffsetLimit) pointOffset = 0
Position(start, end, pointOffset)
}
def exists = this != NoPosition
def shift(offset: Int) =
if (exists) Position(start + offset, end + offset, point - start)
else this
def focus = Position(point)
def startPos = Position(start)
def endPos = Position(end)
def withStart(start: Int) = Position(start, this.end, this.point - start)
def withEnd(end: Int) = Position(this.start, end, this.point - this.start)
def withPoint(point: Int) = Position(this.start, this.end, point - this.start)
def transparent: Position = this /* for now */
}
def Position(start: Int, end: Int, pointOffset: Int = 0): Position =
new Position(
(start & StartEndMask).toLong |
((end & StartEndMask).toLong << StartEndBits) |
(pointOffset.toLong << (StartEndBits * 2)))
def Position(point: Int): Position = Position(point, point, 0)
val NoPosition = new Position(-1L)
case class PositionPrefix(val coords: Long) extends AnyVal {
def start: Int = (coords & StartEndMask).toInt
def point: Int = start + (coords >>> StartEndBits).toInt
def toPosition(end: Int) = Position(start, end, point - start max 0)
}
def PositionPrefix(start: Int, pointOffset: Int = 0): PositionPrefix =
new PositionPrefix(
(start & StartEndMask).toLong | pointOffset.toLong << StartEndBits)
case class SourcePosition(source: SourceFile, pos: Position) {
def point: Int = pos.point
def start: Int = pos.start
def end: Int = pos.end
def exists = pos.exists
}
val NoSourcePosition = SourcePosition(NoSource, NoPosition)
/** The coordinate of a symbol. This is either an index or
* a point position.
*/
class Coord(val encoding: Int) extends AnyVal {
def isIndex = encoding > 0
def isPosition = encoding <= 0
def toIndex: Int = {
assert(isIndex)
encoding - 1
}
def toPosition = {
assert(isPosition)
if (this == NoCoord) NoPosition else Position(1 - encoding)
}
}
def indexCoord(n: Int) = new Coord(n + 1)
def positionCoord(n: Int) = new Coord(-(n + 1))
val NoCoord = new Coord(0)
}
|