pos.mx raw
1 package token
2
3 const PosMax = 1 << 30
4 const Linebase = 1
5 const Colbase = 1
6
7 type Pos struct {
8 base *PosBase
9 line, col uint32
10 }
11
12 func MakePos(base *PosBase, line, col uint32) (p Pos) { return Pos{base, sat32(line), sat32(col)} }
13
14 func (pos *Pos) Pos() (p Pos) { return *pos }
15 func (pos *Pos) IsKnown() (ok bool) { return pos.line > 0 }
16 func (pos *Pos) Base() (p *PosBase) { return pos.base }
17 func (pos *Pos) Line() (n uint32) { return pos.line }
18 func (pos *Pos) Col() (n uint32) { return pos.col }
19
20 func (pos *Pos) FileBase() (p *PosBase) {
21 b := pos.base
22 for b != nil && b != b.pos.base {
23 b = b.pos.base
24 }
25 return b
26 }
27
28 func (pos *Pos) RelFilename() (s string) { return pos.base.Filename() }
29
30 func (pos *Pos) RelLine() (n uint32) {
31 b := pos.base
32 if b.Line() == 0 {
33 return 0
34 }
35 bp := b.Pos()
36 return b.Line() + (pos.Line() - bp.Line())
37 }
38
39 func (pos *Pos) RelCol() (n uint32) {
40 b := pos.base
41 if b.Col() == 0 {
42 return 0
43 }
44 bp := b.Pos()
45 if pos.Line() == bp.Line() {
46 return b.Col() + (pos.Col() - bp.Col())
47 }
48 return pos.Col()
49 }
50
51 func (p *Pos) Cmp(q Pos) (n int32) {
52 pname := p.RelFilename()
53 qname := q.base.Filename()
54 switch {
55 case pname < qname:
56 return -1
57 case pname > qname:
58 return +1
59 }
60
61 pline := p.Line()
62 qline := q.line
63 switch {
64 case pline < qline:
65 return -1
66 case pline > qline:
67 return +1
68 }
69
70 pcol := p.Col()
71 qcol := q.col
72 switch {
73 case pcol < qcol:
74 return -1
75 case pcol > qcol:
76 return +1
77 }
78
79 return 0
80 }
81
82 func (pos *Pos) String() (s string) {
83 rel := position_{pos.RelFilename(), pos.RelLine(), pos.RelCol()}
84 bp := pos.Base().Pos()
85 abs := position_{bp.RelFilename(), pos.Line(), pos.Col()}
86 s = rel.String()
87 if string(rel.filename) != string(abs.filename) || rel.line != abs.line || rel.col != abs.col {
88 s = s | "[" | abs.String() | "]"
89 }
90 return s
91 }
92
93 type position_ struct {
94 filename string
95 line, col uint32
96 }
97
98 func (p *position_) String() (s string) {
99 if p.line == 0 {
100 if p.filename == "" {
101 return "<unknown position>"
102 }
103 return p.filename
104 }
105 if p.col == 0 {
106 return p.filename | ":" | SimpleItoaU32(p.line)
107 }
108 return p.filename | ":" | SimpleItoaU32(p.line) | ":" | SimpleItoaU32(p.col)
109 }
110
111 func SimpleItoaU32(n uint32) (s string) {
112 if n == 0 {
113 return "0"
114 }
115 buf := []byte{:0:10}
116 for n > 0 {
117 push(buf, byte('0'+n%10))
118 n /= 10
119 }
120 for i, j := int32(0), len(buf)-1; i < j; i, j = i+1, j-1 {
121 buf[i], buf[j] = buf[j], buf[i]
122 }
123 return string(buf)
124 }
125
126 type PosBase struct {
127 pos Pos
128 filename string
129 line, col uint32
130 trimmed bool
131 }
132
133 func NewFileBase(filename string) (p *PosBase) {
134 return NewTrimmedFileBase(filename, false)
135 }
136
137 func NewTrimmedFileBase(filename string, trimmed bool) (p *PosBase) {
138 base := &PosBase{MakePos(nil, Linebase, Colbase), filename, Linebase, Colbase, trimmed}
139 base.pos.base = base
140 return base
141 }
142
143 func NewLineBase(pos Pos, filename string, trimmed bool, line, col uint32) (p *PosBase) {
144 return &PosBase{pos, filename, sat32(line), sat32(col), trimmed}
145 }
146
147 func (base *PosBase) IsFileBase() (ok bool) {
148 if base == nil {
149 return false
150 }
151 return base.pos.base == base
152 }
153
154 func (base *PosBase) Pos() (_ Pos) {
155 if base == nil {
156 return
157 }
158 return base.pos
159 }
160
161 func (base *PosBase) Filename() (s string) {
162 if base == nil {
163 return ""
164 }
165 return base.filename
166 }
167
168 func (base *PosBase) Line() (n uint32) {
169 if base == nil {
170 return 0
171 }
172 return base.line
173 }
174
175 func (base *PosBase) Col() (n uint32) {
176 if base == nil {
177 return 0
178 }
179 return base.col
180 }
181
182 func (base *PosBase) Trimmed() (ok bool) {
183 if base == nil {
184 return false
185 }
186 return base.trimmed
187 }
188
189 func sat32(x uint32) (n uint32) {
190 if x > PosMax {
191 return PosMax
192 }
193 return uint32(x)
194 }
195