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 }
137
138
139
140
141 func NewFileBase(filename string) *PosBase {
142 base := &PosBase{MakePos(nil, linebase, colbase), filename, linebase, colbase}
143 base.pos.base = base
144 return base
145 }
146
147
148
149
150
151
152 func NewLineBase(pos Pos, filename string, line, col uint) *PosBase {
153 return &PosBase{pos, filename, sat32(line), sat32(col)}
154 }
155
156 func (base *PosBase) IsFileBase() bool {
157 if base == nil {
158 return false
159 }
160 return base.pos.base == base
161 }
162
163 func (base *PosBase) Pos() (_ Pos) {
164 if base == nil {
165 return
166 }
167 return base.pos
168 }
169
170 func (base *PosBase) Filename() string {
171 if base == nil {
172 return ""
173 }
174 return base.filename
175 }
176
177 func (base *PosBase) Line() uint {
178 if base == nil {
179 return 0
180 }
181 return uint(base.line)
182 }
183
184 func (base *PosBase) Col() uint {
185 if base == nil {
186 return 0
187 }
188 return uint(base.col)
189 }
190
191 func sat32(x uint) uint32 {
192 if x > PosMax {
193 return PosMax
194 }
195 return uint32(x)
196 }
197
View as plain text