mirror of
https://github.com/golang/go
synced 2024-11-19 03:34:41 -07:00
b40df0fb21
This implements a standard way of describing source locations along with printing and parsing of those locations and conversion to and from the token.Pos forms. Change-Id: Ibb3df0a282bc2effb0fa8bd3a51bb0d281b2ffb1 Reviewed-on: https://go-review.googlesource.com/c/tools/+/163778 Run-TryBot: Ian Cottrell <iancottrell@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
122 lines
3.0 KiB
Go
122 lines
3.0 KiB
Go
// Copyright 2019 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package span
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
// Parse returns the location represented by the input.
|
|
// All inputs are valid locations, as they can always be a pure filename.
|
|
func Parse(input string) Span {
|
|
// :0:0#0-0:0#0
|
|
valid := input
|
|
var hold, offset int
|
|
hadCol := false
|
|
suf := rstripSuffix(input)
|
|
if suf.sep == "#" {
|
|
offset = suf.num
|
|
suf = rstripSuffix(suf.remains)
|
|
}
|
|
if suf.sep == ":" {
|
|
valid = suf.remains
|
|
hold = suf.num
|
|
hadCol = true
|
|
suf = rstripSuffix(suf.remains)
|
|
}
|
|
switch {
|
|
case suf.sep == ":":
|
|
p := Point{Line: clamp(suf.num), Column: clamp(hold), Offset: clamp(offset)}
|
|
return Span{
|
|
URI: NewURI(suf.remains),
|
|
Start: p,
|
|
End: p,
|
|
}
|
|
case suf.sep == "-":
|
|
// we have a span, fall out of the case to continue
|
|
default:
|
|
// separator not valid, rewind to either the : or the start
|
|
p := Point{Line: clamp(hold), Column: 0, Offset: clamp(offset)}
|
|
return Span{
|
|
URI: NewURI(valid),
|
|
Start: p,
|
|
End: p,
|
|
}
|
|
}
|
|
// only the span form can get here
|
|
// at this point we still don't know what the numbers we have mean
|
|
// if have not yet seen a : then we might have either a line or a column depending
|
|
// on whether start has a column or not
|
|
// we build an end point and will fix it later if needed
|
|
end := Point{Line: clamp(suf.num), Column: clamp(hold), Offset: clamp(offset)}
|
|
hold, offset = 0, 0
|
|
suf = rstripSuffix(suf.remains)
|
|
if suf.sep == "#" {
|
|
offset = suf.num
|
|
suf = rstripSuffix(suf.remains)
|
|
}
|
|
if suf.sep != ":" {
|
|
// turns out we don't have a span after all, rewind
|
|
return Span{
|
|
URI: NewURI(valid),
|
|
Start: end,
|
|
End: end,
|
|
}
|
|
}
|
|
valid = suf.remains
|
|
hold = suf.num
|
|
suf = rstripSuffix(suf.remains)
|
|
if suf.sep != ":" {
|
|
// line#offset only
|
|
return Span{
|
|
URI: NewURI(valid),
|
|
Start: Point{Line: clamp(hold), Column: 0, Offset: clamp(offset)},
|
|
End: end,
|
|
}
|
|
}
|
|
// we have a column, so if end only had one number, it is also the column
|
|
if !hadCol {
|
|
end.Column = end.Line
|
|
end.Line = clamp(suf.num)
|
|
}
|
|
return Span{
|
|
URI: NewURI(suf.remains),
|
|
Start: Point{Line: clamp(suf.num), Column: clamp(hold), Offset: clamp(offset)},
|
|
End: end,
|
|
}
|
|
}
|
|
|
|
type suffix struct {
|
|
remains string
|
|
sep string
|
|
num int
|
|
}
|
|
|
|
func rstripSuffix(input string) suffix {
|
|
if len(input) == 0 {
|
|
return suffix{"", "", -1}
|
|
}
|
|
remains := input
|
|
num := -1
|
|
// first see if we have a number at the end
|
|
last := strings.LastIndexFunc(remains, func(r rune) bool { return r < '0' || r > '9' })
|
|
if last >= 0 && last < len(remains)-1 {
|
|
number, err := strconv.ParseInt(remains[last+1:], 10, 64)
|
|
if err == nil {
|
|
num = int(number)
|
|
remains = remains[:last+1]
|
|
}
|
|
}
|
|
// now see if we have a trailing separator
|
|
r, w := utf8.DecodeLastRuneInString(remains)
|
|
if r != ':' && r != '#' && r == '#' {
|
|
return suffix{input, "", -1}
|
|
}
|
|
remains = remains[:len(remains)-w]
|
|
return suffix{remains, string(r), num}
|
|
}
|