From e97c8a592f20d390a97db1d516782c56badf258d Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 1 Dec 2016 15:25:07 -0800 Subject: [PATCH] [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 Run-TryBot: Robert Griesemer TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/syntax/pos.go | 83 ++++++++----------- src/cmd/compile/internal/syntax/pos_test.go | 32 +++---- src/cmd/compile/internal/syntax/scanner.go | 2 +- .../compile/internal/syntax/scanner_test.go | 2 +- 4 files changed, 53 insertions(+), 66 deletions(-) diff --git a/src/cmd/compile/internal/syntax/pos.go b/src/cmd/compile/internal/syntax/pos.go index e9ec026af4..48bac7a42e 100644 --- a/src/cmd/compile/internal/syntax/pos.go +++ b/src/cmd/compile/internal/syntax/pos.go @@ -6,10 +6,11 @@ package syntax -import "fmt" +import "strconv" // 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 // 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. -func (p *Pos) Filename() string { - if b := p.base; b != nil { - return b.pos.RelFilename() - } - return "" -} +func (p *Pos) Filename() string { return p.base.Pos().RelFilename() } // Base returns the position base. func (p *Pos) Base() *PosBase { return p.base } // RelFilename returns the filename recorded with the position's base. -func (p *Pos) RelFilename() string { - if b := p.base; b != nil { - return b.filename - } - return "" -} +func (p *Pos) RelFilename() string { return p.base.Filename() } // RelLine returns the line number relative to the positions's base. -func (p *Pos) RelLine() uint { - var line0 uint - if b := p.base; b != nil { - line0 = b.line - p.base.pos.Line() - } - return line0 + p.Line() -} +func (p *Pos) RelLine() uint { b := p.base; return b.Line() + p.Line() - b.Pos().Line() } func (p *Pos) String() string { b := p.base - if b == nil { - return p.lico.String() - } - - if b == b.pos.base { - // base is file base - return fmt.Sprintf("%s:%s", b.filename, p.lico.String()) + if b == b.Pos().base { + // base is file base (incl. nil) + return posString(b.Filename(), p.Line(), p.Col()) } // 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,9 +81,12 @@ type PosBase struct { // NewFileBase returns a new *PosBase for a file with the given filename. func NewFileBase(filename string) *PosBase { - base := &PosBase{filename: filename} - base.pos = MakePos(base, 0, 0) - return base + if filename != "" { + base := &PosBase{filename: filename} + base.pos = MakePos(base, 0, 0) + return base + } + return nil } // NewLinePragmaBase returns a new *PosBase for a line pragma of the form @@ -106,7 +99,7 @@ func NewLinePragmaBase(pos Pos, filename string, line uint) *PosBase { var noPos Pos // 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 { if b != nil { return &b.pos @@ -144,29 +137,21 @@ type lico uint32 // information as line numbers grow bigger; similar to what gcc // does.) const ( - lineW, lineM = 24, 1< lineM { + if line > lineMax { // 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 col = 0 } - return lico(line<> colW } -func (x lico) Col() uint { return uint(x) & colM } -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) -} +func (x lico) Line() uint { return uint(x) >> colBits } +func (x lico) Col() uint { return uint(x) & colMax } diff --git a/src/cmd/compile/internal/syntax/pos_test.go b/src/cmd/compile/internal/syntax/pos_test.go index 65f84113aa..ff29e7b0a3 100644 --- a/src/cmd/compile/internal/syntax/pos_test.go +++ b/src/cmd/compile/internal/syntax/pos_test.go @@ -10,6 +10,7 @@ import ( ) func TestPos(t *testing.T) { + f0 := NewFileBase("") f1 := NewFileBase("f1") f2 := NewLinePragmaBase(Pos{}, "f2", 10) f3 := NewLinePragmaBase(MakePos(f1, 10, 1), "f3", 100) @@ -27,10 +28,11 @@ func TestPos(t *testing.T) { relFilename string relLine uint }{ - {Pos{}, "0", "", 0, 0, "", 0}, - {MakePos(nil, 2, 3), "2:3", "", 2, 3, "", 2}, + {Pos{}, ":0", "", 0, 0, "", 0}, + {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(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(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 line, col uint }{ - {0, "0", 0, 0}, - {makeLico(0, 0), "0", 0, 0}, - {makeLico(0, 1), "0:1", 0, 1}, - {makeLico(1, 0), "1", 1, 0}, - {makeLico(1, 1), "1:1", 1, 1}, - {makeLico(2, 3), "2:3", 2, 3}, - {makeLico(lineM, 1), fmt.Sprintf("%d:1", lineM), lineM, 1}, - {makeLico(lineM+1, 1), fmt.Sprintf("%d:1", lineM), lineM, 1}, // line too large, stick with max. line - {makeLico(1, colM), fmt.Sprintf("1:%d", colM), 1, colM}, - {makeLico(1, colM+1), "1", 1, 0}, // column too large - {makeLico(lineM+1, colM+1), fmt.Sprintf("%d", lineM), lineM, 0}, + {0, ":0", 0, 0}, + {makeLico(0, 0), ":0", 0, 0}, + {makeLico(0, 1), ":0:1", 0, 1}, + {makeLico(1, 0), ":1", 1, 0}, + {makeLico(1, 1), ":1:1", 1, 1}, + {makeLico(2, 3), ":2:3", 2, 3}, + {makeLico(lineMax, 1), fmt.Sprintf(":%d:1", lineMax), lineMax, 1}, + {makeLico(lineMax+1, 1), fmt.Sprintf(":%d:1", lineMax), lineMax, 1}, // line too large, stick with max. line + {makeLico(1, colMax), fmt.Sprintf(":1:%d", colMax), 1, colMax}, + {makeLico(1, colMax+1), ":1", 1, 0}, // column too large + {makeLico(lineMax+1, colMax+1), fmt.Sprintf(":%d", lineMax), lineMax, 0}, } { 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) } } diff --git a/src/cmd/compile/internal/syntax/scanner.go b/src/cmd/compile/internal/syntax/scanner.go index 6fdc0dc6da..77d7a1beef 100644 --- a/src/cmd/compile/internal/syntax/scanner.go +++ b/src/cmd/compile/internal/syntax/scanner.go @@ -577,7 +577,7 @@ func (s *scanner) lineComment() { } nstr := text[i+1:] 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) return } diff --git a/src/cmd/compile/internal/syntax/scanner_test.go b/src/cmd/compile/internal/syntax/scanner_test.go index b319e2c354..b8ec811c18 100644 --- a/src/cmd/compile/internal/syntax/scanner_test.go +++ b/src/cmd/compile/internal/syntax/scanner_test.go @@ -323,7 +323,7 @@ func TestScanErrors(t *testing.T) { {`//line foo:123abc`, "invalid line number: 123abc", 1, 12}, {`/**///line foo:x`, "invalid line number: x", 1, 16}, {`//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 {"package p\n\n\xef", "invalid UTF-8 encoding", 3, 1}, -- 2.48.1