1
0
mirror of https://github.com/golang/go synced 2024-11-19 03:34:41 -07:00
go/internal/span/parse.go
Ian Cottrell b40df0fb21 internal/span: adding a source location package to unify the pos conversions
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>
2019-03-08 14:21:31 +00:00

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}
}