github.com/Rookout/GoSDK@v0.1.48/pkg/services/assembler/internal/src/pos.go (about) 1 // Copyright 2016 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE.assembler file. 4 5 // This file implements the encoding of source positions. 6 7 package src 8 9 import ( 10 "bytes" 11 "fmt" 12 "io" 13 ) 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 type Pos struct { 29 base *PosBase 30 lico 31 } 32 33 34 var NoPos Pos 35 36 37 38 func MakePos(base *PosBase, line, col uint) Pos { 39 return Pos{base, makeLico(line, col)} 40 } 41 42 43 44 45 func (p Pos) IsKnown() bool { 46 return p.base != nil || p.Line() != 0 47 } 48 49 50 51 func (p Pos) Before(q Pos) bool { 52 n, m := p.Filename(), q.Filename() 53 return n < m || n == m && p.lico < q.lico 54 } 55 56 57 58 func (p Pos) After(q Pos) bool { 59 n, m := p.Filename(), q.Filename() 60 return n > m || n == m && p.lico > q.lico 61 } 62 63 func (p Pos) LineNumber() string { 64 if !p.IsKnown() { 65 return "?" 66 } 67 return p.lico.lineNumber() 68 } 69 70 func (p Pos) LineNumberHTML() string { 71 if !p.IsKnown() { 72 return "?" 73 } 74 return p.lico.lineNumberHTML() 75 } 76 77 78 func (p Pos) Filename() string { return p.base.Pos().RelFilename() } 79 80 81 func (p Pos) Base() *PosBase { return p.base } 82 83 84 func (p *Pos) SetBase(base *PosBase) { p.base = base } 85 86 87 func (p Pos) RelFilename() string { return p.base.Filename() } 88 89 90 func (p Pos) RelLine() uint { 91 b := p.base 92 if b.Line() == 0 { 93 94 return 0 95 } 96 return b.Line() + (p.Line() - b.Pos().Line()) 97 } 98 99 100 func (p Pos) RelCol() uint { 101 b := p.base 102 if b.Col() == 0 { 103 104 105 106 107 return 0 108 } 109 if p.Line() == b.Pos().Line() { 110 111 return b.Col() + (p.Col() - b.Pos().Col()) 112 } 113 return p.Col() 114 } 115 116 117 func (p Pos) AbsFilename() string { return p.base.AbsFilename() } 118 119 120 121 func (p Pos) SymFilename() string { return p.base.SymFilename() } 122 123 func (p Pos) String() string { 124 return p.Format(true, true) 125 } 126 127 128 129 130 131 132 func (p Pos) Format(showCol, showOrig bool) string { 133 buf := new(bytes.Buffer) 134 p.WriteTo(buf, showCol, showOrig) 135 return buf.String() 136 } 137 138 139 func (p Pos) WriteTo(w io.Writer, showCol, showOrig bool) { 140 if !p.IsKnown() { 141 io.WriteString(w, "<unknown line number>") 142 return 143 } 144 145 if b := p.base; b == b.Pos().base { 146 147 format(w, p.Filename(), p.Line(), p.Col(), showCol) 148 return 149 } 150 151 152 153 154 155 156 157 158 159 format(w, p.RelFilename(), p.RelLine(), p.RelCol(), showCol) 160 if showOrig { 161 io.WriteString(w, "[") 162 format(w, p.Filename(), p.Line(), p.Col(), showCol) 163 io.WriteString(w, "]") 164 } 165 } 166 167 168 169 func format(w io.Writer, filename string, line, col uint, showCol bool) { 170 io.WriteString(w, filename) 171 io.WriteString(w, ":") 172 fmt.Fprint(w, line) 173 174 if showCol && 0 < col && col < colMax { 175 io.WriteString(w, ":") 176 fmt.Fprint(w, col) 177 } 178 } 179 180 181 func formatstr(filename string, line, col uint, showCol bool) string { 182 buf := new(bytes.Buffer) 183 format(buf, filename, line, col, showCol) 184 return buf.String() 185 } 186 187 188 189 190 191 192 type PosBase struct { 193 pos Pos 194 filename string 195 absFilename string 196 symFilename string 197 line, col uint 198 inl int 199 } 200 201 202 203 func NewFileBase(filename, absFilename string) *PosBase { 204 base := &PosBase{ 205 filename: filename, 206 absFilename: absFilename, 207 symFilename: FileSymPrefix + absFilename, 208 line: 1, 209 col: 1, 210 inl: -1, 211 } 212 base.pos = MakePos(base, 1, 1) 213 return base 214 } 215 216 217 218 219 220 221 222 func NewLinePragmaBase(pos Pos, filename, absFilename string, line, col uint) *PosBase { 223 return &PosBase{pos, filename, absFilename, FileSymPrefix + absFilename, line, col, -1} 224 } 225 226 227 228 func NewInliningBase(old *PosBase, inlTreeIndex int) *PosBase { 229 if old == nil { 230 base := &PosBase{line: 1, col: 1, inl: inlTreeIndex} 231 base.pos = MakePos(base, 1, 1) 232 return base 233 } 234 copy := *old 235 base := © 236 base.inl = inlTreeIndex 237 if old == old.pos.base { 238 base.pos.base = base 239 } 240 return base 241 } 242 243 var noPos Pos 244 245 246 247 func (b *PosBase) Pos() *Pos { 248 if b != nil { 249 return &b.pos 250 } 251 return &noPos 252 } 253 254 255 256 func (b *PosBase) Filename() string { 257 if b != nil { 258 return b.filename 259 } 260 return "" 261 } 262 263 264 265 func (b *PosBase) AbsFilename() string { 266 if b != nil { 267 return b.absFilename 268 } 269 return "" 270 } 271 272 const FileSymPrefix = "gofile.." 273 274 275 276 277 func (b *PosBase) SymFilename() string { 278 if b != nil { 279 return b.symFilename 280 } 281 return FileSymPrefix + "??" 282 } 283 284 285 286 func (b *PosBase) Line() uint { 287 if b != nil { 288 return b.line 289 } 290 return 0 291 } 292 293 294 295 func (b *PosBase) Col() uint { 296 if b != nil { 297 return b.col 298 } 299 return 0 300 } 301 302 303 304 305 func (b *PosBase) InliningIndex() int { 306 if b != nil { 307 return b.inl 308 } 309 return -1 310 } 311 312 313 314 315 316 type lico uint32 317 318 319 320 321 322 323 324 325 326 327 328 const ( 329 lineBits, lineMax = 20, 1<<lineBits - 2 330 bogusLine = 1 331 isStmtBits, isStmtMax = 2, 1<<isStmtBits - 1 332 xlogueBits, xlogueMax = 2, 1<<xlogueBits - 1 333 colBits, colMax = 32 - lineBits - xlogueBits - isStmtBits, 1<<colBits - 1 334 335 isStmtShift = 0 336 isStmtMask = isStmtMax << isStmtShift 337 xlogueShift = isStmtBits + isStmtShift 338 xlogueMask = xlogueMax << xlogueShift 339 colShift = xlogueBits + xlogueShift 340 lineShift = colBits + colShift 341 ) 342 const ( 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 PosDefaultStmt uint = iota 371 PosIsStmt 372 PosNotStmt 373 ) 374 375 type PosXlogue uint 376 377 const ( 378 PosDefaultLogue PosXlogue = iota 379 PosPrologueEnd 380 PosEpilogueBegin 381 ) 382 383 func makeLicoRaw(line, col uint) lico { 384 return lico(line<<lineShift | col<<colShift) 385 } 386 387 388 389 func makeBogusLico() lico { 390 return makeLicoRaw(bogusLine, 0).withIsStmt() 391 } 392 393 func makeLico(line, col uint) lico { 394 if line >= lineMax { 395 396 line = lineMax 397 398 399 col = 0 400 } 401 if col > colMax { 402 403 col = colMax 404 } 405 406 return makeLicoRaw(line, col) 407 } 408 409 func (x lico) Line() uint { return uint(x) >> lineShift } 410 func (x lico) SameLine(y lico) bool { return 0 == (x^y)&^lico(1<<lineShift-1) } 411 func (x lico) Col() uint { return uint(x) >> colShift & colMax } 412 func (x lico) IsStmt() uint { 413 if x == 0 { 414 return PosNotStmt 415 } 416 return uint(x) >> isStmtShift & isStmtMax 417 } 418 func (x lico) Xlogue() PosXlogue { 419 return PosXlogue(uint(x) >> xlogueShift & xlogueMax) 420 } 421 422 423 func (x lico) withNotStmt() lico { 424 return x.withStmt(PosNotStmt) 425 } 426 427 428 func (x lico) withDefaultStmt() lico { 429 return x.withStmt(PosDefaultStmt) 430 } 431 432 433 func (x lico) withIsStmt() lico { 434 return x.withStmt(PosIsStmt) 435 } 436 437 438 func (x lico) withXlogue(xlogue PosXlogue) lico { 439 if x == 0 { 440 if xlogue == 0 { 441 return x 442 } 443 444 x = lico(PosNotStmt << isStmtShift) 445 } 446 return lico(uint(x) & ^uint(xlogueMax<<xlogueShift) | (uint(xlogue) << xlogueShift)) 447 } 448 449 450 func (x lico) withStmt(stmt uint) lico { 451 if x == 0 { 452 return lico(0) 453 } 454 return lico(uint(x) & ^uint(isStmtMax<<isStmtShift) | (stmt << isStmtShift)) 455 } 456 457 func (x lico) lineNumber() string { 458 return fmt.Sprintf("%d", x.Line()) 459 } 460 461 func (x lico) lineNumberHTML() string { 462 if x.IsStmt() == PosDefaultStmt { 463 return fmt.Sprintf("%d", x.Line()) 464 } 465 style, pfx := "b", "+" 466 if x.IsStmt() == PosNotStmt { 467 style = "s" 468 pfx = "" 469 } 470 return fmt.Sprintf("<%s>%s%d</%s>", style, pfx, x.Line(), style) 471 } 472 473 func (x lico) atColumn1() lico { 474 return makeLico(x.Line(), 1).withIsStmt() 475 }