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