[dev.inline] cmd/compile/internal/syntax: simplified position code

Reviewed in and cherry-picked from https://go-review.googlesource.com/#/c/33805/.

Change-Id: I859d9bd5f2256ca78f7b24b330290f7ae600854d
Reviewed-on: https://go-review.googlesource.com/34234
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Robert Griesemer 2016-12-01 15:25:07 -08:00
parent 32bf2829a1
commit e97c8a592f
4 changed files with 53 additions and 66 deletions

View file

@ -6,10 +6,11 @@
package syntax package syntax
import "fmt" import "strconv"
// A Pos encodes a source position consisting of a (line, column) number pair // A Pos encodes a source position consisting of a (line, column) number pair
// and a position base. // and a position base. A zero Pos is a ready to use "unknown" position (empty
// filename, and unknown line and column number).
// //
// The (line, column) values refer to a position in a file independent of any // The (line, column) values refer to a position in a file independent of any
// position base ("absolute" position). They start at 1, and they are unknown // position base ("absolute" position). They start at 1, and they are unknown
@ -33,47 +34,36 @@ func MakePos(base *PosBase, line, col uint) Pos {
} }
// Filename returns the name of the actual file containing this position. // Filename returns the name of the actual file containing this position.
func (p *Pos) Filename() string { func (p *Pos) Filename() string { return p.base.Pos().RelFilename() }
if b := p.base; b != nil {
return b.pos.RelFilename()
}
return ""
}
// Base returns the position base. // Base returns the position base.
func (p *Pos) Base() *PosBase { return p.base } func (p *Pos) Base() *PosBase { return p.base }
// RelFilename returns the filename recorded with the position's base. // RelFilename returns the filename recorded with the position's base.
func (p *Pos) RelFilename() string { func (p *Pos) RelFilename() string { return p.base.Filename() }
if b := p.base; b != nil {
return b.filename
}
return ""
}
// RelLine returns the line number relative to the positions's base. // RelLine returns the line number relative to the positions's base.
func (p *Pos) RelLine() uint { func (p *Pos) RelLine() uint { b := p.base; return b.Line() + p.Line() - b.Pos().Line() }
var line0 uint
if b := p.base; b != nil {
line0 = b.line - p.base.pos.Line()
}
return line0 + p.Line()
}
func (p *Pos) String() string { func (p *Pos) String() string {
b := p.base b := p.base
if b == nil { if b == b.Pos().base {
return p.lico.String() // base is file base (incl. nil)
} return posString(b.Filename(), p.Line(), p.Col())
if b == b.pos.base {
// base is file base
return fmt.Sprintf("%s:%s", b.filename, p.lico.String())
} }
// base is relative // base is relative
return fmt.Sprintf("%s:%s[%s]", b.filename, licoString(p.RelLine(), p.Col()), b.pos.String()) return posString(b.Filename(), p.RelLine(), p.Col()) + "[" + b.Pos().String() + "]"
}
// posString formats a (filename, line, col) tuple as a printable position.
func posString(filename string, line, col uint) string {
s := filename + ":" + strconv.FormatUint(uint64(line), 10)
if col != 0 {
s += ":" + strconv.FormatUint(uint64(col), 10)
}
return s
} }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -91,10 +81,13 @@ type PosBase struct {
// NewFileBase returns a new *PosBase for a file with the given filename. // NewFileBase returns a new *PosBase for a file with the given filename.
func NewFileBase(filename string) *PosBase { func NewFileBase(filename string) *PosBase {
if filename != "" {
base := &PosBase{filename: filename} base := &PosBase{filename: filename}
base.pos = MakePos(base, 0, 0) base.pos = MakePos(base, 0, 0)
return base return base
} }
return nil
}
// NewLinePragmaBase returns a new *PosBase for a line pragma of the form // NewLinePragmaBase returns a new *PosBase for a line pragma of the form
// //line filename:line // //line filename:line
@ -106,7 +99,7 @@ func NewLinePragmaBase(pos Pos, filename string, line uint) *PosBase {
var noPos Pos var noPos Pos
// Pos returns the position at which base is located. // Pos returns the position at which base is located.
// If b == nil, the result is the empty position. // If b == nil, the result is the zero position.
func (b *PosBase) Pos() *Pos { func (b *PosBase) Pos() *Pos {
if b != nil { if b != nil {
return &b.pos return &b.pos
@ -144,29 +137,21 @@ type lico uint32
// information as line numbers grow bigger; similar to what gcc // information as line numbers grow bigger; similar to what gcc
// does.) // does.)
const ( const (
lineW, lineM = 24, 1<<lineW - 1 lineBits, lineMax = 24, 1<<lineBits - 1
colW, colM = 32 - lineW, 1<<colW - 1 colBits, colMax = 32 - lineBits, 1<<colBits - 1
) )
func makeLico(line, col uint) lico { func makeLico(line, col uint) lico {
if line > lineM { if line > lineMax {
// cannot represent line, use max. line so we have some information // cannot represent line, use max. line so we have some information
line = lineM line = lineMax
} }
if col > colM { if col > colMax {
// cannot represent column, use 0 to indicate unknown column // cannot represent column, use 0 to indicate unknown column
col = 0 col = 0
} }
return lico(line<<colW | col) return lico(line<<colBits | col)
} }
func (x lico) Line() uint { return uint(x) >> colW } func (x lico) Line() uint { return uint(x) >> colBits }
func (x lico) Col() uint { return uint(x) & colM } func (x lico) Col() uint { return uint(x) & colMax }
func (x lico) String() string { return licoString(x.Line(), x.Col()) }
func licoString(line, col uint) string {
if col == 0 {
return fmt.Sprintf("%d", line)
}
return fmt.Sprintf("%d:%d", line, col)
}

View file

@ -10,6 +10,7 @@ import (
) )
func TestPos(t *testing.T) { func TestPos(t *testing.T) {
f0 := NewFileBase("")
f1 := NewFileBase("f1") f1 := NewFileBase("f1")
f2 := NewLinePragmaBase(Pos{}, "f2", 10) f2 := NewLinePragmaBase(Pos{}, "f2", 10)
f3 := NewLinePragmaBase(MakePos(f1, 10, 1), "f3", 100) f3 := NewLinePragmaBase(MakePos(f1, 10, 1), "f3", 100)
@ -27,10 +28,11 @@ func TestPos(t *testing.T) {
relFilename string relFilename string
relLine uint relLine uint
}{ }{
{Pos{}, "0", "", 0, 0, "", 0}, {Pos{}, ":0", "", 0, 0, "", 0},
{MakePos(nil, 2, 3), "2:3", "", 2, 3, "", 2}, {MakePos(nil, 2, 3), ":2:3", "", 2, 3, "", 2},
{MakePos(f0, 2, 3), ":2:3", "", 2, 3, "", 2},
{MakePos(f1, 1, 1), "f1:1:1", "f1", 1, 1, "f1", 1}, {MakePos(f1, 1, 1), "f1:1:1", "f1", 1, 1, "f1", 1},
{MakePos(f2, 7, 10), "f2:16:10[0]", "", 7, 10, "f2", 16}, {MakePos(f2, 7, 10), "f2:16:10[:0]", "", 7, 10, "f2", 16},
{MakePos(f3, 12, 7), "f3:101:7[f1:10:1]", "f1", 12, 7, "f3", 101}, {MakePos(f3, 12, 7), "f3:101:7[f1:10:1]", "f1", 12, 7, "f3", 101},
{MakePos(f4, 25, 1), "f4:114:1[f3:99:1[f1:10:1]]", "f3", 25, 1, "f4", 114}, // doesn't occur in Go code {MakePos(f4, 25, 1), "f4:114:1[f3:99:1[f1:10:1]]", "f3", 25, 1, "f4", 114}, // doesn't occur in Go code
} { } {
@ -66,20 +68,20 @@ func TestLico(t *testing.T) {
string string string string
line, col uint line, col uint
}{ }{
{0, "0", 0, 0}, {0, ":0", 0, 0},
{makeLico(0, 0), "0", 0, 0}, {makeLico(0, 0), ":0", 0, 0},
{makeLico(0, 1), "0:1", 0, 1}, {makeLico(0, 1), ":0:1", 0, 1},
{makeLico(1, 0), "1", 1, 0}, {makeLico(1, 0), ":1", 1, 0},
{makeLico(1, 1), "1:1", 1, 1}, {makeLico(1, 1), ":1:1", 1, 1},
{makeLico(2, 3), "2:3", 2, 3}, {makeLico(2, 3), ":2:3", 2, 3},
{makeLico(lineM, 1), fmt.Sprintf("%d:1", lineM), lineM, 1}, {makeLico(lineMax, 1), fmt.Sprintf(":%d:1", lineMax), lineMax, 1},
{makeLico(lineM+1, 1), fmt.Sprintf("%d:1", lineM), lineM, 1}, // line too large, stick with max. line {makeLico(lineMax+1, 1), fmt.Sprintf(":%d:1", lineMax), lineMax, 1}, // line too large, stick with max. line
{makeLico(1, colM), fmt.Sprintf("1:%d", colM), 1, colM}, {makeLico(1, colMax), fmt.Sprintf(":1:%d", colMax), 1, colMax},
{makeLico(1, colM+1), "1", 1, 0}, // column too large {makeLico(1, colMax+1), ":1", 1, 0}, // column too large
{makeLico(lineM+1, colM+1), fmt.Sprintf("%d", lineM), lineM, 0}, {makeLico(lineMax+1, colMax+1), fmt.Sprintf(":%d", lineMax), lineMax, 0},
} { } {
x := test.x x := test.x
if got := x.String(); got != test.string { if got := posString("", x.Line(), x.Col()); got != test.string {
t.Errorf("%s: got %q", test.string, got) t.Errorf("%s: got %q", test.string, got)
} }
} }

View file

@ -577,7 +577,7 @@ func (s *scanner) lineComment() {
} }
nstr := text[i+1:] nstr := text[i+1:]
n, err := strconv.Atoi(nstr) n, err := strconv.Atoi(nstr)
if err != nil || n <= 0 || n > lineM { if err != nil || n <= 0 || n > lineMax {
s.error_at(s.line0, s.col0-uint(len(nstr)), "invalid line number: "+nstr) s.error_at(s.line0, s.col0-uint(len(nstr)), "invalid line number: "+nstr)
return return
} }

View file

@ -323,7 +323,7 @@ func TestScanErrors(t *testing.T) {
{`//line foo:123abc`, "invalid line number: 123abc", 1, 12}, {`//line foo:123abc`, "invalid line number: 123abc", 1, 12},
{`/**///line foo:x`, "invalid line number: x", 1, 16}, {`/**///line foo:x`, "invalid line number: x", 1, 16},
{`//line foo:0`, "invalid line number: 0", 1, 12}, {`//line foo:0`, "invalid line number: 0", 1, 12},
{fmt.Sprintf(`//line foo:%d`, lineM+1), fmt.Sprintf("invalid line number: %d", lineM+1), 1, 12}, {fmt.Sprintf(`//line foo:%d`, lineMax+1), fmt.Sprintf("invalid line number: %d", lineMax+1), 1, 12},
// former problem cases // former problem cases
{"package p\n\n\xef", "invalid UTF-8 encoding", 3, 1}, {"package p\n\n\xef", "invalid UTF-8 encoding", 3, 1},