]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/syntax: remove dependency on cmd/internal/src
authorRobert Griesemer <gri@golang.org>
Wed, 3 Jan 2018 00:58:37 +0000 (16:58 -0800)
committerRobert Griesemer <gri@golang.org>
Mon, 26 Feb 2018 18:27:15 +0000 (18:27 +0000)
For dependency reasons, the data structure implementing source
positions in the compiler is in cmd/internal/src. It contains
highly compiler specific details (e.g. inlining index).

This change introduces a parallel but simpler position
representation, defined in the syntax package, which removes
that package's dependency on cmd/internal/src, and also removes
the need to deal with certain filename-specific operations
(defined by the needs of the compiler) in the syntax package.
As a result, the syntax package becomes again a compiler-
independent, stand-alone package that at some point might
replace (or augment) the existing top-level go/* syntax-related
packages.

Additionally, line directives that update column numbers
are now correctly tracked through the syntax package, with
additional tests added. (The respective changes also need to
be made in cmd/internal/src; i.e., the compiler accepts but
still ignores column numbers in line directives.)

This change comes at the cost of a new position translation
step, but that step is cheap because it only needs to do real
work if the position base changed (i.e., if there is a new file,
or new line directive).

There is no noticeable impact on overall compiler performance
measured with `compilebench -count 5 -alloc`:

name       old time/op       new time/op       delta
Template         220ms ± 8%        228ms ±18%    ~     (p=0.548 n=5+5)
Unicode          119ms ±11%        113ms ± 5%    ~     (p=0.056 n=5+5)
GoTypes          684ms ± 6%        677ms ± 3%    ~     (p=0.841 n=5+5)
Compiler         3.19s ± 7%        3.01s ± 1%    ~     (p=0.095 n=5+5)
SSA              7.92s ± 8%        7.79s ± 1%    ~     (p=0.690 n=5+5)
Flate            141ms ± 7%        139ms ± 4%    ~     (p=0.548 n=5+5)
GoParser         173ms ±12%        171ms ± 4%    ~     (p=1.000 n=5+5)
Reflect          417ms ± 5%        411ms ± 3%    ~     (p=0.548 n=5+5)
Tar              205ms ± 5%        198ms ± 2%    ~     (p=0.690 n=5+5)
XML              232ms ± 4%        229ms ± 4%    ~     (p=0.690 n=5+5)
StdCmd           28.7s ± 5%        28.2s ± 2%    ~     (p=0.421 n=5+5)

name       old user-time/op  new user-time/op  delta
Template         269ms ± 4%        265ms ± 5%    ~     (p=0.421 n=5+5)
Unicode          153ms ± 7%        149ms ± 3%    ~     (p=0.841 n=5+5)
GoTypes          850ms ± 7%        862ms ± 4%    ~     (p=0.841 n=5+5)
Compiler         4.01s ± 5%        3.86s ± 0%    ~     (p=0.190 n=5+4)
SSA              10.9s ± 4%        10.8s ± 2%    ~     (p=0.548 n=5+5)
Flate            166ms ± 7%        167ms ± 6%    ~     (p=1.000 n=5+5)
GoParser         204ms ± 8%        206ms ± 7%    ~     (p=0.841 n=5+5)
Reflect          514ms ± 5%        508ms ± 4%    ~     (p=0.548 n=5+5)
Tar              245ms ± 6%        244ms ± 3%    ~     (p=0.690 n=5+5)
XML              280ms ± 4%        278ms ± 4%    ~     (p=0.841 n=5+5)

name       old alloc/op      new alloc/op      delta
Template        37.9MB ± 0%       37.9MB ± 0%    ~     (p=0.841 n=5+5)
Unicode         28.8MB ± 0%       28.8MB ± 0%    ~     (p=0.841 n=5+5)
GoTypes          113MB ± 0%        113MB ± 0%    ~     (p=0.151 n=5+5)
Compiler         468MB ± 0%        468MB ± 0%  -0.01%  (p=0.032 n=5+5)
SSA             1.50GB ± 0%       1.50GB ± 0%    ~     (p=0.548 n=5+5)
Flate           24.4MB ± 0%       24.4MB ± 0%    ~     (p=1.000 n=5+5)
GoParser        30.7MB ± 0%       30.7MB ± 0%    ~     (p=1.000 n=5+5)
Reflect         76.5MB ± 0%       76.5MB ± 0%    ~     (p=0.548 n=5+5)
Tar             38.9MB ± 0%       38.9MB ± 0%    ~     (p=0.222 n=5+5)
XML             41.6MB ± 0%       41.6MB ± 0%    ~     (p=0.548 n=5+5)

name       old allocs/op     new allocs/op     delta
Template          382k ± 0%         382k ± 0%  +0.01%  (p=0.008 n=5+5)
Unicode           343k ± 0%         343k ± 0%    ~     (p=0.841 n=5+5)
GoTypes          1.19M ± 0%        1.19M ± 0%  +0.01%  (p=0.008 n=5+5)
Compiler         4.53M ± 0%        4.53M ± 0%  +0.03%  (p=0.008 n=5+5)
SSA              12.4M ± 0%        12.4M ± 0%  +0.00%  (p=0.008 n=5+5)
Flate             235k ± 0%         235k ± 0%    ~     (p=0.079 n=5+5)
GoParser          318k ± 0%         318k ± 0%    ~     (p=0.730 n=5+5)
Reflect           978k ± 0%         978k ± 0%    ~     (p=1.000 n=5+5)
Tar               393k ± 0%         393k ± 0%    ~     (p=0.056 n=5+5)
XML               405k ± 0%         405k ± 0%    ~     (p=0.548 n=5+5)

name       old text-bytes    new text-bytes    delta
HelloSize        672kB ± 0%        672kB ± 0%    ~     (all equal)
CmdGoSize       7.12MB ± 0%       7.12MB ± 0%    ~     (all equal)

name       old data-bytes    new data-bytes    delta
HelloSize        133kB ± 0%        133kB ± 0%    ~     (all equal)
CmdGoSize        390kB ± 0%        390kB ± 0%    ~     (all equal)

name       old exe-bytes     new exe-bytes     delta
HelloSize       1.07MB ± 0%       1.07MB ± 0%    ~     (all equal)
CmdGoSize       11.2MB ± 0%       11.2MB ± 0%    ~     (all equal)

Passes toolstash compare.

For #22662.

Change-Id: I19edb53dd9675af57f7122cb7dba2a6d8bdcc3da
Reviewed-on: https://go-review.googlesource.com/94515
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
14 files changed:
src/cmd/compile/fmt_test.go
src/cmd/compile/internal/gc/closure.go
src/cmd/compile/internal/gc/lex.go
src/cmd/compile/internal/gc/lex_test.go
src/cmd/compile/internal/gc/noder.go
src/cmd/compile/internal/gc/swt.go
src/cmd/compile/internal/syntax/branches.go
src/cmd/compile/internal/syntax/nodes.go
src/cmd/compile/internal/syntax/nodes_test.go
src/cmd/compile/internal/syntax/parser.go
src/cmd/compile/internal/syntax/parser_test.go
src/cmd/compile/internal/syntax/pos.go [new file with mode: 0644]
src/cmd/compile/internal/syntax/printer_test.go
src/cmd/compile/internal/syntax/syntax.go

index f3f66a66aea856cc5277382b8684bfd94e395ce1..03e6e2ee4cc9682badb7e6af45f838bc4ea40c7c 100644 (file)
@@ -650,14 +650,14 @@ var knownFormats = map[string]string{
        "cmd/compile/internal/syntax.Expr %#v":            "",
        "cmd/compile/internal/syntax.Node %T":             "",
        "cmd/compile/internal/syntax.Operator %s":         "",
+       "cmd/compile/internal/syntax.Pos %s":              "",
+       "cmd/compile/internal/syntax.Pos %v":              "",
        "cmd/compile/internal/syntax.position %s":         "",
        "cmd/compile/internal/syntax.token %q":            "",
        "cmd/compile/internal/syntax.token %s":            "",
        "cmd/compile/internal/types.EType %d":             "",
        "cmd/compile/internal/types.EType %s":             "",
        "cmd/compile/internal/types.EType %v":             "",
-       "cmd/internal/src.Pos %s":                         "",
-       "cmd/internal/src.Pos %v":                         "",
        "error %v":                                        "",
        "float64 %.2f":                                    "",
        "float64 %.3f":                                    "",
index d3af16e1764d93ea9c20ce1a20f054e81a51c5dd..1713b5129c5e8198f9e507e149ae6c441ab083ac 100644 (file)
@@ -53,7 +53,7 @@ func (p *noder) funcLit(expr *syntax.FuncLit) *Node {
 
        body := p.stmts(expr.Body.List)
 
-       lineno = Ctxt.PosTable.XPos(expr.Body.Rbrace)
+       lineno = p.makeXPos(expr.Body.Rbrace)
        if len(body) == 0 {
                body = []*Node{nod(OEMPTY, nil, nil)}
        }
index 9d14f5338234a2fade8f4eccd9d893d86d2d3d99..22f720e066cf71120a0610a6cf1dc0c8c4086052 100644 (file)
@@ -105,7 +105,7 @@ func pragmaValue(verb string) syntax.Pragma {
 }
 
 // pragcgo is called concurrently if files are parsed concurrently.
-func (p *noder) pragcgo(pos src.Pos, text string) string {
+func (p *noder) pragcgo(pos syntax.Pos, text string) string {
        f := pragmaFields(text)
 
        verb := f[0][3:] // skip "go:"
index a56f3963ba3ea9924df4e2ba783379b0d439e3ef..965a84e3e8c5f333d666a919cfce88bbf6e8164b 100644 (file)
@@ -5,7 +5,7 @@
 package gc
 
 import (
-       "cmd/internal/src"
+       "cmd/compile/internal/syntax"
        "testing"
 )
 
@@ -22,7 +22,6 @@ func eq(a, b []string) bool {
 }
 
 func TestPragmaFields(t *testing.T) {
-
        var tests = []struct {
                in   string
                want []string
@@ -49,7 +48,6 @@ func TestPragmaFields(t *testing.T) {
 }
 
 func TestPragcgo(t *testing.T) {
-
        var tests = []struct {
                in   string
                want string
@@ -73,8 +71,9 @@ func TestPragcgo(t *testing.T) {
        }
 
        var p noder
+       var nopos syntax.Pos
        for _, tt := range tests {
-               got := p.pragcgo(src.NoPos, tt.in)
+               got := p.pragcgo(nopos, tt.in)
                if got != tt.want {
                        t.Errorf("pragcgo(%q) = %q; want %q", tt.in, got, tt.want)
                        continue
index 6f32e52ec80917bd02182988afd55e0267a0f3f9..9418bc5c2fd292b9e8877d0e2c5816f34a4720ed 100644 (file)
@@ -25,30 +25,33 @@ func parseFiles(filenames []string) uint {
        sem := make(chan struct{}, runtime.GOMAXPROCS(0)+10)
 
        for _, filename := range filenames {
-               p := &noder{err: make(chan syntax.Error)}
+               p := &noder{
+                       basemap: make(map[*syntax.PosBase]*src.PosBase),
+                       err:     make(chan syntax.Error),
+               }
                noders = append(noders, p)
 
                go func(filename string) {
                        sem <- struct{}{}
                        defer func() { <-sem }()
                        defer close(p.err)
-                       base := src.NewFileBase(filename, absFilename(filename))
+                       base := syntax.NewFileBase(filename)
 
                        f, err := os.Open(filename)
                        if err != nil {
-                               p.error(syntax.Error{Pos: src.MakePos(base, 0, 0), Msg: err.Error()})
+                               p.error(syntax.Error{Pos: syntax.MakePos(base, 0, 0), Msg: err.Error()})
                                return
                        }
                        defer f.Close()
 
-                       p.file, _ = syntax.Parse(base, f, p.error, p.pragma, fileh, syntax.CheckBranches) // errors are tracked via p.error
+                       p.file, _ = syntax.Parse(base, f, p.error, p.pragma, syntax.CheckBranches) // errors are tracked via p.error
                }(filename)
        }
 
        var lines uint
        for _, p := range noders {
                for e := range p.err {
-                       yyerrorpos(e.Pos, "%s", e.Msg)
+                       p.yyerrorpos(e.Pos, "%s", e.Msg)
                }
 
                p.node()
@@ -65,12 +68,54 @@ func parseFiles(filenames []string) uint {
        return lines
 }
 
-func yyerrorpos(pos src.Pos, format string, args ...interface{}) {
-       yyerrorl(Ctxt.PosTable.XPos(pos), format, args...)
+// makeSrcPosBase translates from a *syntax.PosBase to a *src.PosBase.
+func (p *noder) makeSrcPosBase(b0 *syntax.PosBase) *src.PosBase {
+       // fast path: most likely PosBase hasn't changed
+       if p.basecache.last == b0 {
+               return p.basecache.base
+       }
+
+       b1, ok := p.basemap[b0]
+       if !ok {
+               fn := b0.Filename()
+               if p0 := b0.Pos(); p0.IsKnown() {
+                       // line directive base
+                       //
+                       // (A syntax.PosBase position is the position at which the PosBase's
+                       // new line and column are starting. For //line directives, that is
+                       // the position of the line following the directive. src.PosBases
+                       // on the other hand use the position of the line directive instead.
+                       // Hence the `p0.Line()-1` below.)
+                       //
+                       // TODO(gri) Once we implement /*line directives, we need to adjust
+                       //           src.MakePos accordingly.
+                       p1 := src.MakePos(p.makeSrcPosBase(p0.Base()), p0.Line()-1, p0.Col())
+                       b1 = src.NewLinePragmaBase(p1, fn, fileh(fn), b0.Line())
+               } else {
+                       // file base
+                       b1 = src.NewFileBase(fn, absFilename(fn))
+               }
+               p.basemap[b0] = b1
+       }
+
+       // update cache
+       p.basecache.last = b0
+       p.basecache.base = b1
+
+       return b1
+}
+
+func (p *noder) makeXPos(pos syntax.Pos) (_ src.XPos) {
+       return Ctxt.PosTable.XPos(src.MakePos(p.makeSrcPosBase(pos.Base()), pos.Line(), pos.Col()))
+}
+
+func (p *noder) yyerrorpos(pos syntax.Pos, format string, args ...interface{}) {
+       yyerrorl(p.makeXPos(pos), format, args...)
 }
 
 var pathPrefix string
 
+// TODO(gri) Can we eliminate fileh in favor of absFilename?
 func fileh(name string) string {
        return objabi.AbsFile("", name, pathPrefix)
 }
@@ -81,6 +126,12 @@ func absFilename(name string) string {
 
 // noder transforms package syntax's AST into a Node tree.
 type noder struct {
+       basemap   map[*syntax.PosBase]*src.PosBase
+       basecache struct {
+               last *syntax.PosBase
+               base *src.PosBase
+       }
+
        file       *syntax.File
        linknames  []linkname
        pragcgobuf string
@@ -100,7 +151,7 @@ func (p *noder) funcbody(old ScopeID) {
        p.scope = old
 }
 
-func (p *noder) openScope(pos src.Pos) {
+func (p *noder) openScope(pos syntax.Pos) {
        types.Markdcl()
 
        if trackScopes {
@@ -111,7 +162,7 @@ func (p *noder) openScope(pos src.Pos) {
        }
 }
 
-func (p *noder) closeScope(pos src.Pos) {
+func (p *noder) closeScope(pos syntax.Pos) {
        types.Popdcl()
 
        if trackScopes {
@@ -121,8 +172,8 @@ func (p *noder) closeScope(pos src.Pos) {
        }
 }
 
-func (p *noder) markScope(pos src.Pos) {
-       xpos := Ctxt.PosTable.XPos(pos)
+func (p *noder) markScope(pos syntax.Pos) {
+       xpos := p.makeXPos(pos)
        if i := len(Curfn.Func.Marks); i > 0 && Curfn.Func.Marks[i-1].Pos == xpos {
                Curfn.Func.Marks[i-1].Scope = p.scope
        } else {
@@ -145,7 +196,7 @@ func (p *noder) closeAnotherScope() {
 
 // linkname records a //go:linkname directive.
 type linkname struct {
-       pos    src.Pos
+       pos    syntax.Pos
        local  string
        remote string
 }
@@ -163,7 +214,7 @@ func (p *noder) node() {
                if imported_unsafe {
                        lookup(n.local).Linkname = n.remote
                } else {
-                       yyerrorpos(n.pos, "//go:linkname only allowed in Go files that import \"unsafe\"")
+                       p.yyerrorpos(n.pos, "//go:linkname only allowed in Go files that import \"unsafe\"")
                }
        }
 
@@ -403,7 +454,7 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node {
                }
                f.Nbody.Set(body)
 
-               lineno = Ctxt.PosTable.XPos(fun.Body.Rbrace)
+               lineno = p.makeXPos(fun.Body.Rbrace)
                f.Func.Endlineno = lineno
        } else {
                if pure_go || strings.HasPrefix(f.funcname(), "init.") {
@@ -497,7 +548,7 @@ func (p *noder) expr(expr syntax.Expr) *Node {
                        l[i] = p.wrapname(expr.ElemList[i], e)
                }
                n.List.Set(l)
-               lineno = Ctxt.PosTable.XPos(expr.Rbrace)
+               lineno = p.makeXPos(expr.Rbrace)
                return n
        case *syntax.KeyValueExpr:
                return p.nod(expr, OKEY, p.expr(expr.Key), p.wrapname(expr.Value, p.expr(expr.Value)))
@@ -943,7 +994,7 @@ func (p *noder) assignList(expr syntax.Expr, defn *Node, colas bool) []*Node {
 
                name, ok := expr.(*syntax.Name)
                if !ok {
-                       yyerrorpos(expr.Pos(), "non-name %v on left side of :=", p.expr(expr))
+                       p.yyerrorpos(expr.Pos(), "non-name %v on left side of :=", p.expr(expr))
                        newOrErr = true
                        continue
                }
@@ -954,7 +1005,7 @@ func (p *noder) assignList(expr syntax.Expr, defn *Node, colas bool) []*Node {
                }
 
                if seen[sym] {
-                       yyerrorpos(expr.Pos(), "%v repeated on left side of :=", sym)
+                       p.yyerrorpos(expr.Pos(), "%v repeated on left side of :=", sym)
                        newOrErr = true
                        continue
                }
@@ -1057,7 +1108,7 @@ func (p *noder) switchStmt(stmt *syntax.SwitchStmt) *Node {
        return n
 }
 
-func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *Node, rbrace src.Pos) []*Node {
+func (p *noder) caseClauses(clauses []*syntax.CaseClause, tswitch *Node, rbrace syntax.Pos) []*Node {
        var nodes []*Node
        for i, clause := range clauses {
                p.lineno(clause)
@@ -1113,7 +1164,7 @@ func (p *noder) selectStmt(stmt *syntax.SelectStmt) *Node {
        return n
 }
 
-func (p *noder) commClauses(clauses []*syntax.CommClause, rbrace src.Pos) []*Node {
+func (p *noder) commClauses(clauses []*syntax.CommClause, rbrace syntax.Pos) []*Node {
        var nodes []*Node
        for i, clause := range clauses {
                p.lineno(clause)
@@ -1298,7 +1349,7 @@ func (p *noder) setlineno(src_ syntax.Node, dst *Node) *Node {
                // TODO(mdempsky): Shouldn't happen. Fix package syntax.
                return dst
        }
-       dst.Pos = Ctxt.PosTable.XPos(pos)
+       dst.Pos = p.makeXPos(pos)
        return dst
 }
 
@@ -1311,7 +1362,7 @@ func (p *noder) lineno(n syntax.Node) {
                // TODO(mdempsky): Shouldn't happen. Fix package syntax.
                return
        }
-       lineno = Ctxt.PosTable.XPos(pos)
+       lineno = p.makeXPos(pos)
 }
 
 // error is called concurrently if files are parsed concurrently.
@@ -1332,7 +1383,7 @@ var allowedStdPragmas = map[string]bool{
 }
 
 // pragma is called concurrently if files are parsed concurrently.
-func (p *noder) pragma(pos src.Pos, text string) syntax.Pragma {
+func (p *noder) pragma(pos syntax.Pos, text string) syntax.Pragma {
        switch {
        case strings.HasPrefix(text, "line "):
                // line directives are handled by syntax package
@@ -1393,8 +1444,8 @@ func (p *noder) pragma(pos src.Pos, text string) syntax.Pragma {
 // contain cgo directives, and for security reasons
 // (primarily misuse of linker flags), other files are not.
 // See golang.org/issue/23672.
-func isCgoGeneratedFile(pos src.Pos) bool {
-       return strings.HasPrefix(filepath.Base(filepath.Clean(pos.AbsFilename())), "_cgo_")
+func isCgoGeneratedFile(pos syntax.Pos) bool {
+       return strings.HasPrefix(filepath.Base(filepath.Clean(fileh(pos.Base().Filename()))), "_cgo_")
 }
 
 // safeArg reports whether arg is a "safe" command-line argument,
index 8509795790a6864e928b99ff9d89db2f638daab4..8d425506d3407bc278bc29962ed822d106d20fa1 100644 (file)
@@ -568,7 +568,7 @@ Outer:
                if !ok {
                        // First entry for this hash.
                        nn = append(nn, c.node)
-                       seen[c.hash] = nn[len(nn)-1 : len(nn):len(nn)]
+                       seen[c.hash] = nn[len(nn)-1 : len(nn) : len(nn)]
                        continue
                }
                for _, n := range prev {
index 2fd97a4a678a8902d06bb4c91e5bd1157ad5c9e2..a03e2734d26a3096159c2940f1dc712f36e095e3 100644 (file)
@@ -4,10 +4,7 @@
 
 package syntax
 
-import (
-       "cmd/internal/src"
-       "fmt"
-)
+import "fmt"
 
 // TODO(gri) consider making this part of the parser code
 
@@ -62,11 +59,11 @@ type label struct {
 
 type block struct {
        parent *block       // immediately enclosing block, or nil
-       start  src.Pos      // start of block
+       start  Pos          // start of block
        lstmt  *LabeledStmt // labeled statement associated with this block, or nil
 }
 
-func (ls *labelScope) err(pos src.Pos, format string, args ...interface{}) {
+func (ls *labelScope) err(pos Pos, format string, args ...interface{}) {
        ls.errh(Error{pos, fmt.Sprintf(format, args...)})
 }
 
@@ -132,14 +129,14 @@ type targets struct {
 // list of unresolved (forward) gotos. parent is the immediately enclosing
 // block (or nil), ctxt provides information about the enclosing statements,
 // and lstmt is the labeled statement associated with this block, or nil.
-func (ls *labelScope) blockBranches(parent *block, ctxt targets, lstmt *LabeledStmt, start src.Pos, body []Stmt) []*BranchStmt {
+func (ls *labelScope) blockBranches(parent *block, ctxt targets, lstmt *LabeledStmt, start Pos, body []Stmt) []*BranchStmt {
        b := &block{parent: parent, start: start, lstmt: lstmt}
 
-       var varPos src.Pos
+       var varPos Pos
        var varName Expr
        var fwdGotos, badGotos []*BranchStmt
 
-       recordVarDecl := func(pos src.Pos, name Expr) {
+       recordVarDecl := func(pos Pos, name Expr) {
                varPos = pos
                varName = name
                // Any existing forward goto jumping over the variable
@@ -160,7 +157,7 @@ func (ls *labelScope) blockBranches(parent *block, ctxt targets, lstmt *LabeledS
                return false
        }
 
-       innerBlock := func(ctxt targets, start src.Pos, body []Stmt) {
+       innerBlock := func(ctxt targets, start Pos, body []Stmt) {
                // Unresolved forward gotos from the inner block
                // become forward gotos for the current block.
                fwdGotos = append(fwdGotos, ls.blockBranches(b, ctxt, lstmt, start, body)...)
index d7183bd8fb00dc9cf06a7c6010ecc39cbacd3577..8df9fd5c4e483f0a7ec1cf973ecf1d8a8da92337 100644 (file)
@@ -4,8 +4,6 @@
 
 package syntax
 
-import "cmd/internal/src"
-
 // ----------------------------------------------------------------------------
 // Nodes
 
@@ -18,18 +16,18 @@ type Node interface {
        //    (IndexExpr, IfStmt, etc.) is the position of a token uniquely
        //    associated with that production; usually the left-most one
        //    ('[' for IndexExpr, 'if' for IfStmt, etc.)
-       Pos() src.Pos
+       Pos() Pos
        aNode()
 }
 
 type node struct {
        // commented out for now since not yet used
        // doc  *Comment // nil means no comment(s) attached
-       pos src.Pos
+       pos Pos
 }
 
-func (n *node) Pos() src.Pos { return n.pos }
-func (*node) aNode()         {}
+func (n *node) Pos() Pos { return n.pos }
+func (*node) aNode()     {}
 
 // ----------------------------------------------------------------------------
 // Files
@@ -149,7 +147,7 @@ type (
                Type     Expr // nil means no literal type
                ElemList []Expr
                NKeys    int // number of elements with keys
-               Rbrace   src.Pos
+               Rbrace   Pos
                expr
        }
 
@@ -328,7 +326,7 @@ type (
 
        BlockStmt struct {
                List   []Stmt
-               Rbrace src.Pos
+               Rbrace Pos
                stmt
        }
 
@@ -396,13 +394,13 @@ type (
                Init   SimpleStmt
                Tag    Expr
                Body   []*CaseClause
-               Rbrace src.Pos
+               Rbrace Pos
                stmt
        }
 
        SelectStmt struct {
                Body   []*CommClause
-               Rbrace src.Pos
+               Rbrace Pos
                stmt
        }
 )
@@ -425,14 +423,14 @@ type (
        CaseClause struct {
                Cases Expr // nil means default clause
                Body  []Stmt
-               Colon src.Pos
+               Colon Pos
                node
        }
 
        CommClause struct {
                Comm  SimpleStmt // send or receive stmt; nil means default clause
                Body  []Stmt
-               Colon src.Pos
+               Colon Pos
                node
        }
 )
index 433ae30661bcded722f632eb7809a197ed66e693..a39f08c1a42cb56b1e940282a438831224c1fd7d 100644 (file)
@@ -291,7 +291,7 @@ func testPos(t *testing.T, list []test, prefix, suffix string, extract func(*Fil
                }
 
                // build syntax tree
-               file, err := Parse(nil, strings.NewReader(src), nil, nil, nil, 0)
+               file, err := Parse(nil, strings.NewReader(src), nil, nil, 0)
                if err != nil {
                        t.Errorf("parse error: %s: %v (%s)", src, err, test.nodetyp)
                        continue
index 8f9775afe7f078ab07152b79cd6cc65b0eae2bb2..fd200f7381addfd8da44a432336544b7f0ffadaf 100644 (file)
@@ -5,7 +5,6 @@
 package syntax
 
 import (
-       "cmd/internal/src"
        "fmt"
        "io"
        "strconv"
@@ -16,26 +15,24 @@ const debug = false
 const trace = false
 
 type parser struct {
-       file  *src.PosBase
-       errh  ErrorHandler
-       fileh FilenameHandler
-       mode  Mode
+       file *PosBase
+       errh ErrorHandler
+       mode Mode
        scanner
 
-       base   *src.PosBase // current position base
-       first  error        // first error encountered
-       errcnt int          // number of errors encountered
-       pragma Pragma       // pragma flags
+       base   *PosBase // current position base
+       first  error    // first error encountered
+       errcnt int      // number of errors encountered
+       pragma Pragma   // pragma flags
 
        fnest  int    // function nesting level (for error handling)
        xnest  int    // expression nesting level (for complit ambiguity resolution)
        indent []byte // tracing support
 }
 
-func (p *parser) init(file *src.PosBase, r io.Reader, errh ErrorHandler, pragh PragmaHandler, fileh FilenameHandler, mode Mode) {
+func (p *parser) init(file *PosBase, r io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) {
        p.file = file
        p.errh = errh
-       p.fileh = fileh
        p.mode = mode
        p.scanner.init(
                r,
@@ -52,15 +49,25 @@ func (p *parser) init(file *src.PosBase, r io.Reader, errh ErrorHandler, pragh P
 
                        // otherwise it must be a comment containing a line or go: directive
                        text := commentText(msg)
-                       col += 2 // text starts after // or /*
                        if strings.HasPrefix(text, "line ") {
-                               p.updateBase(line, col+5, text[5:])
+                               var pos Pos // position immediately following the comment
+                               if msg[1] == '/' {
+                                       // line comment
+                                       pos = MakePos(p.file, line+1, colbase)
+                               } else {
+                                       // regular comment
+                                       // (if the comment spans multiple lines it's not
+                                       // a valid line directive and will be discarded
+                                       // by updateBase)
+                                       pos = MakePos(p.file, line, col+uint(len(msg)))
+                               }
+                               p.updateBase(pos, line, col+2+5, text[5:]) // +2 to skip over // or /*
                                return
                        }
 
                        // go: directive (but be conservative and test)
                        if pragh != nil && strings.HasPrefix(text, "go:") {
-                               p.pragma |= pragh(p.posAt(line, col), text)
+                               p.pragma |= pragh(p.posAt(line, col+2), text) // +2 to skip over // or /*
                        }
                },
                directives,
@@ -76,9 +83,7 @@ func (p *parser) init(file *src.PosBase, r io.Reader, errh ErrorHandler, pragh P
        p.indent = nil
 }
 
-const lineMax = 1<<24 - 1 // TODO(gri) this limit is defined for src.Pos - fix
-
-func (p *parser) updateBase(line, col uint, text string) {
+func (p *parser) updateBase(pos Pos, line, col uint, text string) {
        i, n, ok := trailingDigits(text)
        if i == 0 {
                return // ignore (not a line directive)
@@ -96,26 +101,25 @@ func (p *parser) updateBase(line, col uint, text string) {
                //line filename:line:col
                i, i2 = i2, i
                n, n2 = n2, n
-               if n2 == 0 {
+               if n2 == 0 || n2 > PosMax {
                        p.errorAt(p.posAt(line, col+i2), "invalid column number: "+text[i2:])
                        return
                }
                text = text[:i2-1] // lop off :col
+       } else {
+               //line filename:line
+               n2 = colbase // use start of line for column
        }
 
-       if n == 0 || n > lineMax {
+       if n == 0 || n > PosMax {
                p.errorAt(p.posAt(line, col+i), "invalid line number: "+text[i:])
                return
        }
 
        filename := text[:i-1] // lop off :line
-       absFilename := filename
-       if p.fileh != nil {
-               absFilename = p.fileh(filename)
-       }
+       // TODO(gri) handle case where filename doesn't change (see #22662)
 
-       // TODO(gri) pass column n2 to NewLinePragmaBase
-       p.base = src.NewLinePragmaBase(src.MakePos(p.file, line, col), filename, absFilename, uint(n) /*uint(n2)*/)
+       p.base = NewLineBase(pos, filename, n, n2)
 }
 
 func commentText(s string) string {
@@ -162,12 +166,12 @@ func (p *parser) want(tok token) {
 // Error handling
 
 // posAt returns the Pos value for (line, col) and the current position base.
-func (p *parser) posAt(line, col uint) src.Pos {
-       return src.MakePos(p.base, line, col)
+func (p *parser) posAt(line, col uint) Pos {
+       return MakePos(p.base, line, col)
 }
 
 // error reports an error at the given position.
-func (p *parser) errorAt(pos src.Pos, msg string) {
+func (p *parser) errorAt(pos Pos, msg string) {
        err := Error{pos, msg}
        if p.first == nil {
                p.first = err
@@ -180,7 +184,7 @@ func (p *parser) errorAt(pos src.Pos, msg string) {
 }
 
 // syntaxErrorAt reports a syntax error at the given position.
-func (p *parser) syntaxErrorAt(pos src.Pos, msg string) {
+func (p *parser) syntaxErrorAt(pos Pos, msg string) {
        if trace {
                p.print("syntax error: " + msg)
        }
@@ -237,7 +241,7 @@ func tokstring(tok token) string {
 }
 
 // Convenience methods using the current token position.
-func (p *parser) pos() src.Pos           { return p.posAt(p.line, p.col) }
+func (p *parser) pos() Pos               { return p.posAt(p.line, p.col) }
 func (p *parser) syntaxError(msg string) { p.syntaxErrorAt(p.pos(), msg) }
 
 // The stopset contains keywords that start a statement.
@@ -417,7 +421,7 @@ func isEmptyFuncDecl(dcl Decl) bool {
 // list = "(" { f sep } ")" |
 //        "{" { f sep } "}" . // sep is optional before ")" or "}"
 //
-func (p *parser) list(open, sep, close token, f func() bool) src.Pos {
+func (p *parser) list(open, sep, close token, f func() bool) Pos {
        p.want(open)
 
        var done bool
@@ -1064,7 +1068,7 @@ func (p *parser) type_() Expr {
        return typ
 }
 
-func newIndirect(pos src.Pos, typ Expr) Expr {
+func newIndirect(pos Pos, typ Expr) Expr {
        o := new(Operation)
        o.pos = pos
        o.Op = Mul
@@ -1276,7 +1280,7 @@ func (p *parser) funcResult() []*Field {
        return nil
 }
 
-func (p *parser) addField(styp *StructType, pos src.Pos, name *Name, typ Expr, tag *BasicLit) {
+func (p *parser) addField(styp *StructType, pos Pos, name *Name, typ Expr, tag *BasicLit) {
        if tag != nil {
                for i := len(styp.FieldList) - len(styp.TagList); i > 0; i-- {
                        styp.TagList = append(styp.TagList, nil)
@@ -1694,7 +1698,7 @@ func (p *parser) newRangeClause(lhs Expr, def bool) *RangeClause {
        return r
 }
 
-func (p *parser) newAssignStmt(pos src.Pos, op Operator, lhs, rhs Expr) *AssignStmt {
+func (p *parser) newAssignStmt(pos Pos, op Operator, lhs, rhs Expr) *AssignStmt {
        a := new(AssignStmt)
        a.pos = pos
        a.Op = op
@@ -1818,7 +1822,7 @@ func (p *parser) header(keyword token) (init SimpleStmt, cond Expr, post SimpleS
 
        var condStmt SimpleStmt
        var semi struct {
-               pos src.Pos
+               pos Pos
                lit string // valid if pos.IsKnown()
        }
        if p.tok != _Lbrace {
index 592163bb51ac0c604d740347e90176aa6174d264..cfac2e0118ae431f1f07104459683c1e579597c8 100644 (file)
@@ -6,7 +6,6 @@ package syntax
 
 import (
        "bytes"
-       "cmd/internal/src"
        "flag"
        "fmt"
        "io/ioutil"
@@ -131,7 +130,7 @@ func verifyPrint(filename string, ast1 *File) {
                panic(err)
        }
 
-       ast2, err := Parse(src.NewFileBase(filename, filename), &buf1, nil, nil, nil, 0)
+       ast2, err := Parse(NewFileBase(filename), &buf1, nil, nil, 0)
        if err != nil {
                panic(err)
        }
@@ -155,7 +154,7 @@ func verifyPrint(filename string, ast1 *File) {
 }
 
 func TestIssue17697(t *testing.T) {
-       _, err := Parse(nil, bytes.NewReader(nil), nil, nil, nil, 0) // return with parser error, don't panic
+       _, err := Parse(nil, bytes.NewReader(nil), nil, nil, 0) // return with parser error, don't panic
        if err == nil {
                t.Errorf("no error reported")
        }
@@ -181,6 +180,11 @@ func TestParseFile(t *testing.T) {
        }
 }
 
+// Make sure (PosMax + 1) doesn't overflow when converted to default
+// type int (when passed as argument to fmt.Sprintf) on 32bit platforms
+// (see test cases below).
+var tooLarge int = PosMax + 1
+
 func TestLineDirectives(t *testing.T) {
        // valid line directives lead to a syntax error after them
        const valid = "syntax error: package statement must be first"
@@ -191,11 +195,11 @@ func TestLineDirectives(t *testing.T) {
                line, col uint // 0-based
        }{
                // ignored //line directives
-               {"//\n", valid, "", 2 - linebase, 0},            // no directive
-               {"//line\n", valid, "", 2 - linebase, 0},        // missing colon
-               {"//line foo\n", valid, "", 2 - linebase, 0},    // missing colon
-               {"  //line foo:\n", valid, "", 2 - linebase, 0}, // not a line start
-               {"//  line foo:\n", valid, "", 2 - linebase, 0}, // space between // and line
+               {"//\n", valid, "", 1, 0},            // no directive
+               {"//line\n", valid, "", 1, 0},        // missing colon
+               {"//line foo\n", valid, "", 1, 0},    // missing colon
+               {"  //line foo:\n", valid, "", 1, 0}, // not a line start
+               {"//  line foo:\n", valid, "", 1, 0}, // space between // and line
 
                // invalid //line directives with one colon
                {"//line :\n", "invalid line number: ", "", 0, 8},
@@ -206,7 +210,7 @@ func TestLineDirectives(t *testing.T) {
                {"//line foo:1 \n", "invalid line number: 1 ", "", 0, 11},
                {"//line foo:-12\n", "invalid line number: -12", "", 0, 11},
                {"//line C:foo:0\n", "invalid line number: 0", "", 0, 13},
-               {fmt.Sprintf("//line foo:%d\n", lineMax+1), fmt.Sprintf("invalid line number: %d", lineMax+1), "", 0, 11},
+               {fmt.Sprintf("//line foo:%d\n", tooLarge), fmt.Sprintf("invalid line number: %d", tooLarge), "", 0, 11},
 
                // invalid //line directives with two colons
                {"//line ::\n", "invalid line number: ", "", 0, 9},
@@ -217,27 +221,33 @@ func TestLineDirectives(t *testing.T) {
 
                {"//line :123:0\n", "invalid column number: 0", "", 0, 12},
                {"//line foo:123:0\n", "invalid column number: 0", "", 0, 15},
+               {fmt.Sprintf("//line foo:10:%d\n", tooLarge), fmt.Sprintf("invalid column number: %d", tooLarge), "", 0, 14},
 
-               // effect of valid //line directives on positions
+               // effect of valid //line directives on lines
                {"//line foo:123\n   foo", valid, "foo", 123 - linebase, 3},
                {"//line  foo:123\n   foo", valid, " foo", 123 - linebase, 3},
                {"//line foo:123\n//line bar:345\nfoo", valid, "bar", 345 - linebase, 0},
                {"//line C:foo:123\n", valid, "C:foo", 123 - linebase, 0},
-               {"//line " + runtime.GOROOT() + "/src/a/a.go:123\n   foo", valid, "$GOROOT/src/a/a.go", 123 - linebase, 3},
-               {"//line :x:1\n", valid, ":x", 0, 0},
-               {"//line foo ::1\n", valid, "foo :", 0, 0},
+               {"//line /src/a/a.go:123\n   foo", valid, "/src/a/a.go", 123 - linebase, 3},
+               {"//line :x:1\n", valid, ":x", 1 - linebase, 0},
+               {"//line foo ::1\n", valid, "foo :", 1 - linebase, 0},
                {"//line foo:123abc:1\n", valid, "foo:123abc", 0, 0},
                {"//line foo :123:1\n", valid, "foo ", 123 - linebase, 0},
                {"//line ::123\n", valid, ":", 123 - linebase, 0},
 
-               // TODO(gri) add tests to verify correct column changes, once implemented
+               // effect of valid //line directives on columns
+               {"//line :x:1:10\n", valid, ":x", 1 - linebase, 10 - colbase},
+               {"//line foo ::1:2\n", valid, "foo :", 1 - linebase, 2 - colbase},
+               {"//line foo:123abc:1:1000\n", valid, "foo:123abc", 1 - linebase, 1000 - colbase},
+               {"//line foo :123:1000\n\n", valid, "foo ", 124 - linebase, 0},
+               {"//line ::123:1234\n", valid, ":", 123 - linebase, 1234 - colbase},
 
                // ignored /*line directives
-               {"/**/", valid, "", 1 - linebase, 4},             // no directive
-               {"/*line*/", valid, "", 1 - linebase, 8},         // missing colon
-               {"/*line foo*/", valid, "", 1 - linebase, 12},    // missing colon
-               {"  //line foo:*/", valid, "", 1 - linebase, 15}, // not a line start
-               {"/*  line foo:*/", valid, "", 1 - linebase, 15}, // space between // and line
+               {"/**/", valid, "", 0, 4},             // no directive
+               {"/*line*/", valid, "", 0, 8},         // missing colon
+               {"/*line foo*/", valid, "", 0, 12},    // missing colon
+               {"  //line foo:*/", valid, "", 0, 15}, // not a line start
+               {"/*  line foo:*/", valid, "", 0, 15}, // space between // and line
 
                // invalid /*line directives with one colon
                {"/*line :*/", "invalid line number: ", "", 0, 8},
@@ -247,7 +257,7 @@ func TestLineDirectives(t *testing.T) {
                {"/*line foo:0*/", "invalid line number: 0", "", 0, 11},
                {"/*line foo:1 */", "invalid line number: 1 ", "", 0, 11},
                {"/*line C:foo:0*/", "invalid line number: 0", "", 0, 13},
-               {fmt.Sprintf("/*line foo:%d*/", lineMax+1), fmt.Sprintf("invalid line number: %d", lineMax+1), "", 0, 11},
+               {fmt.Sprintf("/*line foo:%d*/", tooLarge), fmt.Sprintf("invalid line number: %d", tooLarge), "", 0, 11},
 
                // invalid /*line directives with two colons
                {"/*line ::*/", "invalid line number: ", "", 0, 9},
@@ -258,31 +268,27 @@ func TestLineDirectives(t *testing.T) {
 
                {"/*line :123:0*/", "invalid column number: 0", "", 0, 12},
                {"/*line foo:123:0*/", "invalid column number: 0", "", 0, 15},
+               {fmt.Sprintf("/*line foo:10:%d*/", tooLarge), fmt.Sprintf("invalid column number: %d", tooLarge), "", 0, 14},
 
-               // effect of valid /*line directives on positions
-               // TODO(gri) remove \n after directives once line number is computed correctly
-               {"/*line foo:123*/\n   foo", valid, "foo", 123 - linebase, 3},
+               // effect of valid /*line directives on lines
+               {"/*line foo:123*/   foo", valid, "foo", 123 - linebase, 3},
                {"/*line foo:123*/\n//line bar:345\nfoo", valid, "bar", 345 - linebase, 0},
-               {"/*line C:foo:123*/\n", valid, "C:foo", 123 - linebase, 0},
-               {"/*line " + runtime.GOROOT() + "/src/a/a.go:123*/\n   foo", valid, "$GOROOT/src/a/a.go", 123 - linebase, 3},
-               {"/*line :x:1*/\n", valid, ":x", 1 - linebase, 0},
-               {"/*line foo ::1*/\n", valid, "foo :", 1 - linebase, 0},
-               {"/*line foo:123abc:1*/\n", valid, "foo:123abc", 1 - linebase, 0},
-               {"/*line foo :123:1*/\n", valid, "foo ", 123 - linebase, 0},
-               {"/*line ::123*/\n", valid, ":", 123 - linebase, 0},
-
-               // test effect of /*line directive on (relative) position information for this line
-               // TODO(gri) add these tests
-
-               // TODO(gri) add tests to verify correct column changes, once implemented
+               {"/*line C:foo:123*/", valid, "C:foo", 123 - linebase, 0},
+               {"/*line /src/a/a.go:123*/   foo", valid, "/src/a/a.go", 123 - linebase, 3},
+               {"/*line :x:1*/", valid, ":x", 1 - linebase, 0},
+               {"/*line foo ::1*/", valid, "foo :", 1 - linebase, 0},
+               {"/*line foo:123abc:1*/", valid, "foo:123abc", 1 - linebase, 0},
+               {"/*line foo :123:10*/", valid, "foo ", 123 - linebase, 10 - colbase},
+               {"/*line ::123*/", valid, ":", 123 - linebase, 0},
+
+               // effect of valid /*line directives on columns
+               {"/*line :x:1:10*/", valid, ":x", 1 - linebase, 10 - colbase},
+               {"/*line foo ::1:2*/", valid, "foo :", 1 - linebase, 2 - colbase},
+               {"/*line foo:123abc:1:1000*/", valid, "foo:123abc", 1 - linebase, 1000 - colbase},
+               {"/*line foo :123:1000*/\n", valid, "foo ", 124 - linebase, 0},
+               {"/*line ::123:1234*/", valid, ":", 123 - linebase, 1234 - colbase},
        } {
-               fileh := func(name string) string {
-                       if strings.HasPrefix(name, runtime.GOROOT()) {
-                               return "$GOROOT" + name[len(runtime.GOROOT()):]
-                       }
-                       return name
-               }
-               _, err := Parse(nil, strings.NewReader(test.src), nil, nil, fileh, 0)
+               _, err := Parse(nil, strings.NewReader(test.src), nil, nil, 0)
                if err == nil {
                        t.Errorf("%s: no error reported", test.src)
                        continue
@@ -295,14 +301,16 @@ func TestLineDirectives(t *testing.T) {
                if msg := perr.Msg; msg != test.msg {
                        t.Errorf("%s: got msg = %q; want %q", test.src, msg, test.msg)
                }
-               if filename := perr.Pos.AbsFilename(); filename != test.filename {
+
+               pos := perr.Pos
+               if filename := pos.RelFilename(); filename != test.filename {
                        t.Errorf("%s: got filename = %q; want %q", test.src, filename, test.filename)
                }
-               if line := perr.Pos.RelLine(); line-linebase != test.line {
-                       t.Errorf("%s: got line = %d; want %d", test.src, line-linebase, test.line)
+               if line := pos.RelLine(); line != test.line+linebase {
+                       t.Errorf("%s: got line = %d; want %d", test.src, line, test.line+linebase)
                }
-               if col := perr.Pos.Col(); col-colbase != test.col {
-                       t.Errorf("%s: got col = %d; want %d", test.src, col-colbase, test.col)
+               if col := pos.RelCol(); col != test.col+colbase {
+                       t.Errorf("%s: got col = %d; want %d", test.src, col, test.col+colbase)
                }
        }
 }
diff --git a/src/cmd/compile/internal/syntax/pos.go b/src/cmd/compile/internal/syntax/pos.go
new file mode 100644 (file)
index 0000000..00e603e
--- /dev/null
@@ -0,0 +1,109 @@
+// Copyright 2018 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 syntax
+
+import "fmt"
+
+// PosMax is the largest line or column value that can be represented without loss.
+// Incoming values (arguments) larger than PosMax will be set to PosMax.
+const PosMax = 1 << 30
+
+// A Pos represents an absolute (line, col) source position
+// with a reference to position base for computing relative
+// (to a file, or line directive) position information.
+// Pos values are intentionally light-weight so that they
+// can be created without too much concern about space use.
+type Pos struct {
+       base      *PosBase
+       line, col uint32
+}
+
+// MakePos returns a new Pos for the given PosBase, line and column.
+func MakePos(base *PosBase, line, col uint) Pos { return Pos{base, sat32(line), sat32(col)} }
+
+// TODO(gri) IsKnown makes an assumption about linebase < 1.
+//           Maybe we should check for Base() != nil instead.
+
+func (pos Pos) IsKnown() bool  { return pos.line > 0 }
+func (pos Pos) Base() *PosBase { return pos.base }
+func (pos Pos) Line() uint     { return uint(pos.line) }
+func (pos Pos) Col() uint      { return uint(pos.col) }
+
+func (pos Pos) RelFilename() string { b := pos.Base(); return b.Filename() }
+func (pos Pos) RelLine() uint       { b := pos.Base(); return b.Line() + (pos.Line() - b.Pos().Line()) }
+func (pos Pos) RelCol() uint {
+       b := pos.Base()
+       if pos.Line() == b.Pos().Line() {
+               // pos on same line as pos base => column is relative to pos base
+               return b.Col() + (pos.Col() - b.Pos().Col())
+       }
+       return pos.Col()
+}
+
+func (pos Pos) String() string {
+       s := fmt.Sprintf("%s:%d:%d", pos.RelFilename(), pos.RelLine(), pos.RelCol())
+       if bpos := pos.Base().Pos(); bpos.IsKnown() {
+               s += fmt.Sprintf("[%s:%d:%d]", bpos.RelFilename(), pos.Line(), pos.Col())
+       }
+       return s
+}
+
+// A PosBase represents the base for relative position information:
+// At position pos, the relative position is filename:line:col.
+type PosBase struct {
+       pos       Pos
+       filename  string
+       line, col uint32
+}
+
+// NewFileBase returns a new PosBase for the given filename.
+// The PosBase position is unknown in this case.
+func NewFileBase(filename string) *PosBase {
+       return &PosBase{filename: filename}
+}
+
+// NewLineBase returns a new PosBase for a line directive "line filename:line:col"
+// relative to pos, which is the position of the character immediately following
+// the comment containing the line directive. For a directive in a line comment,
+// that position is the beginning of the next line (i.e., the newline character
+// belongs to the line comment).
+func NewLineBase(pos Pos, filename string, line, col uint) *PosBase {
+       return &PosBase{pos, filename, sat32(line), sat32(col)}
+}
+
+func (base *PosBase) Pos() (_ Pos) {
+       if base == nil {
+               return
+       }
+       return base.pos
+}
+
+func (base *PosBase) Filename() string {
+       if base == nil {
+               return ""
+       }
+       return base.filename
+}
+
+func (base *PosBase) Line() uint {
+       if base == nil {
+               return 0
+       }
+       return uint(base.line)
+}
+
+func (base *PosBase) Col() uint {
+       if base == nil {
+               return 0
+       }
+       return uint(base.col)
+}
+
+func sat32(x uint) uint32 {
+       if x > PosMax {
+               return PosMax
+       }
+       return uint32(x)
+}
index 6f19846e22d51bdc9edaf2c2133493949734a778..bc78f0126583364f1aa596aa293bb4dd8fd79fba 100644 (file)
@@ -34,7 +34,7 @@ func TestPrintString(t *testing.T) {
                "package p; type _ = int; type T1 = struct{}; type ( _ = *struct{}; T2 = float32 )",
                // TODO(gri) expand
        } {
-               ast, err := Parse(nil, strings.NewReader(want), nil, nil, nil, 0)
+               ast, err := Parse(nil, strings.NewReader(want), nil, nil, 0)
                if err != nil {
                        t.Error(err)
                        continue
index 7de7d4d9fae7f7095bf0d29d23fc699c24ec8245..b8c387419f25b2ec890a1f5ad733994d3f4631b2 100644 (file)
@@ -5,7 +5,6 @@
 package syntax
 
 import (
-       "cmd/internal/src"
        "fmt"
        "io"
        "os"
@@ -21,7 +20,7 @@ const (
 
 // Error describes a syntax error. Error implements the error interface.
 type Error struct {
-       Pos src.Pos
+       Pos Pos
        Msg string
 }
 
@@ -42,11 +41,7 @@ type Pragma uint16
 // A PragmaHandler is used to process //go: directives as
 // they're scanned. The returned Pragma value will be unioned into the
 // next FuncDecl node.
-type PragmaHandler func(pos src.Pos, text string) Pragma
-
-// A FilenameHandler is used to process each filename encountered
-// in //line directives. The returned value is used as the absolute filename.
-type FilenameHandler func(name string) string
+type PragmaHandler func(pos Pos, text string) Pragma
 
 // Parse parses a single Go source file from src and returns the corresponding
 // syntax tree. If there are errors, Parse will return the first error found,
@@ -60,10 +55,7 @@ type FilenameHandler func(name string) string
 //
 // If pragh != nil, it is called with each pragma encountered.
 //
-// If fileh != nil, it is called to process each filename
-// encountered in //line directives.
-//
-func Parse(base *src.PosBase, src io.Reader, errh ErrorHandler, pragh PragmaHandler, fileh FilenameHandler, mode Mode) (_ *File, first error) {
+func Parse(base *PosBase, src io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) (_ *File, first error) {
        defer func() {
                if p := recover(); p != nil {
                        if err, ok := p.(Error); ok {
@@ -75,7 +67,7 @@ func Parse(base *src.PosBase, src io.Reader, errh ErrorHandler, pragh PragmaHand
        }()
 
        var p parser
-       p.init(base, src, errh, pragh, fileh, mode)
+       p.init(base, src, errh, pragh, mode)
        p.next()
        return p.fileOrNil(), p.first
 }
@@ -90,5 +82,5 @@ func ParseFile(filename string, errh ErrorHandler, pragh PragmaHandler, mode Mod
                return nil, err
        }
        defer f.Close()
-       return Parse(src.NewFileBase(filename, filename), f, errh, pragh, nil, mode)
+       return Parse(NewFileBase(filename), f, errh, pragh, mode)
 }