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