aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2016-12-09 17:15:05 -0800
committerRobert Griesemer <gri@golang.org>2017-01-09 22:33:23 +0000
commit4808fc444307fa683bf3df6d55f9ad1828891a36 (patch)
treeca3c3cc1b0b52d467091bca2a42f2722154854d9 /src/cmd/compile
parent2d429f01bd917c42e66e1991eab9c2e33d813d16 (diff)
downloadgo-4808fc444307fa683bf3df6d55f9ad1828891a36.tar.gz
go-4808fc444307fa683bf3df6d55f9ad1828891a36.zip
[dev.inline] cmd/internal/src: replace src.Pos with syntax.Pos
This replaces the src.Pos LineHist-based position tracking with the syntax.Pos implementation and updates all uses. The LineHist table is not used anymore - the respective code is still there but should be removed eventually. CL forthcoming. Passes toolstash -cmp when comparing to the master repo (with the exception of a couple of swapped assembly instructions, likely due to different instruction scheduling because the line-based sorting has changed; though this is won't affect correctness). The sizes of various important compiler data structures have increased significantly (see the various sizes_test.go files); this is probably the reason for an increase of compilation times (to be addressed). Here are the results of compilebench -count 5, run on a "quiet" machine (no apps running besides a terminal): name old time/op new time/op delta Template 256ms ± 1% 280ms ±15% +9.54% (p=0.008 n=5+5) Unicode 132ms ± 1% 132ms ± 1% ~ (p=0.690 n=5+5) GoTypes 891ms ± 1% 917ms ± 2% +2.88% (p=0.008 n=5+5) Compiler 3.84s ± 2% 3.99s ± 2% +3.95% (p=0.016 n=5+5) MakeBash 47.1s ± 1% 47.2s ± 2% ~ (p=0.841 n=5+5) name old user-ns/op new user-ns/op delta Template 309M ± 1% 326M ± 2% +5.18% (p=0.008 n=5+5) Unicode 165M ± 1% 168M ± 4% ~ (p=0.421 n=5+5) GoTypes 1.14G ± 2% 1.18G ± 1% +3.47% (p=0.008 n=5+5) Compiler 5.00G ± 1% 5.16G ± 1% +3.12% (p=0.008 n=5+5) Change-Id: I241c4246cdff627d7ecb95cac23060b38f9775ec Reviewed-on: https://go-review.googlesource.com/34273 Run-TryBot: Robert Griesemer <gri@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Diffstat (limited to 'src/cmd/compile')
-rw-r--r--src/cmd/compile/fmt_test.go2
-rw-r--r--src/cmd/compile/internal/gc/alg.go4
-rw-r--r--src/cmd/compile/internal/gc/bexport.go3
-rw-r--r--src/cmd/compile/internal/gc/init.go3
-rw-r--r--src/cmd/compile/internal/gc/lex.go7
-rw-r--r--src/cmd/compile/internal/gc/main.go16
-rw-r--r--src/cmd/compile/internal/gc/noder.go92
-rw-r--r--src/cmd/compile/internal/gc/sizeof_test.go10
-rw-r--r--src/cmd/compile/internal/gc/ssa.go25
-rw-r--r--src/cmd/compile/internal/gc/subr.go90
-rw-r--r--src/cmd/compile/internal/gc/util.go2
-rw-r--r--src/cmd/compile/internal/ssa/sizeof_test.go4
-rw-r--r--src/cmd/compile/internal/syntax/dumper_test.go2
-rw-r--r--src/cmd/compile/internal/syntax/nodes.go8
-rw-r--r--src/cmd/compile/internal/syntax/parser.go24
-rw-r--r--src/cmd/compile/internal/syntax/parser_test.go11
-rw-r--r--src/cmd/compile/internal/syntax/pos.go180
-rw-r--r--src/cmd/compile/internal/syntax/pos_test.go130
-rw-r--r--src/cmd/compile/internal/syntax/printer_test.go2
-rw-r--r--src/cmd/compile/internal/syntax/syntax.go21
20 files changed, 150 insertions, 486 deletions
diff --git a/src/cmd/compile/fmt_test.go b/src/cmd/compile/fmt_test.go
index f0f0852c55..88e9ba2b7b 100644
--- a/src/cmd/compile/fmt_test.go
+++ b/src/cmd/compile/fmt_test.go
@@ -650,11 +650,11 @@ var knownFormats = map[string]string{
"cmd/compile/internal/syntax.Node %T": "",
"cmd/compile/internal/syntax.Operator %d": "",
"cmd/compile/internal/syntax.Operator %s": "",
- "cmd/compile/internal/syntax.Pos %s": "",
"cmd/compile/internal/syntax.token %d": "",
"cmd/compile/internal/syntax.token %q": "",
"cmd/compile/internal/syntax.token %s": "",
"cmd/internal/obj.As %v": "",
+ "cmd/internal/src.Pos %s": "",
"error %v": "",
"float64 %.2f": "",
"float64 %.3f": "",
diff --git a/src/cmd/compile/internal/gc/alg.go b/src/cmd/compile/internal/gc/alg.go
index 50b75aa09f..3c71cea33a 100644
--- a/src/cmd/compile/internal/gc/alg.go
+++ b/src/cmd/compile/internal/gc/alg.go
@@ -189,7 +189,7 @@ func genhash(sym *Sym, t *Type) {
fmt.Printf("genhash %v %v\n", sym, t)
}
- lineno = src.MakePos(1) // less confusing than end of input
+ lineno = src.MakePos(nil, 1, 0) // less confusing than end of input
dclcontext = PEXTERN
markdcl()
@@ -365,7 +365,7 @@ func geneq(sym *Sym, t *Type) {
fmt.Printf("geneq %v %v\n", sym, t)
}
- lineno = src.MakePos(1) // less confusing than end of input
+ lineno = src.MakePos(nil, 1, 0) // less confusing than end of input
dclcontext = PEXTERN
markdcl()
diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go
index 438446147a..dbf2d6e166 100644
--- a/src/cmd/compile/internal/gc/bexport.go
+++ b/src/cmd/compile/internal/gc/bexport.go
@@ -591,7 +591,8 @@ func (p *exporter) pos(n *Node) {
func fileLine(n *Node) (file string, line int) {
if n != nil {
- file, line = Ctxt.LineHist.AbsFileLine(int(n.Pos.Line()))
+ file = n.Pos.AbsFilename()
+ line = int(n.Pos.Line())
}
return
}
diff --git a/src/cmd/compile/internal/gc/init.go b/src/cmd/compile/internal/gc/init.go
index 5693052fdf..bfb0da5071 100644
--- a/src/cmd/compile/internal/gc/init.go
+++ b/src/cmd/compile/internal/gc/init.go
@@ -75,6 +75,9 @@ func anyinit(n []*Node) bool {
}
func fninit(n []*Node) {
+ // This code is using the last value of lineno for position information
+ // (see comment in noder.go, noder.file method, for details).
+
nf := initfix(n)
if !anyinit(nf) {
return
diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go
index 00dc975f2c..f92387036b 100644
--- a/src/cmd/compile/internal/gc/lex.go
+++ b/src/cmd/compile/internal/gc/lex.go
@@ -12,11 +12,8 @@ import (
"strings"
)
-// lexlineno is the line number _after_ the most recently read rune.
-// In particular, it's advanced (or rewound) as newlines are read (or unread).
-var lexlineno src.Pos
-
-// lineno is the line number at the start of the most recently lexed token.
+// lineno is the source position at the start of the most recently lexed token.
+// TODO(gri) rename and eventually remove
var lineno src.Pos
func isSpace(c rune) bool {
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index a3487afb44..aa917c735b 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -186,7 +186,7 @@ func Main() {
obj.Flagcount("r", "debug generated wrappers", &Debug['r'])
flag.BoolVar(&flag_race, "race", false, "enable race detector")
obj.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
- flag.StringVar(&Ctxt.LineHist.TrimPathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
+ flag.StringVar(&pathPrefix, "trimpath", "", "remove `prefix` from recorded source file paths")
flag.BoolVar(&safemode, "u", false, "reject unsafe code")
obj.Flagcount("v", "increase debug verbosity", &Debug['v'])
obj.Flagcount("w", "debug type checking", &Debug['w'])
@@ -300,31 +300,23 @@ func Main() {
blockgen = 1
dclcontext = PEXTERN
nerrors = 0
- lexlineno = src.MakePos(1)
timings.Start("fe", "loadsys")
loadsys()
timings.Start("fe", "parse")
- lexlineno0 := lexlineno
+ var lines uint
for _, infile = range flag.Args() {
- linehistpush(infile)
block = 1
iota_ = -1000000
imported_unsafe = false
- parseFile(infile)
+ lines += parseFile(infile)
if nsyntaxerrors != 0 {
errorexit()
}
-
- // Instead of converting EOF into '\n' in getc and count it as an extra line
- // for the line history to work, and which then has to be corrected elsewhere,
- // just add a line here.
- lexlineno = src.MakePos(lexlineno.Line() + 1)
- linehistpop()
}
timings.Stop()
- timings.AddEvent(int64(lexlineno.Line()-lexlineno0.Line()), "lines")
+ timings.AddEvent(int64(lines), "lines")
testdclstack()
mkpackage(localpkg.Name) // final import not used checks
diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go
index cdfa84aa4c..7376814b43 100644
--- a/src/cmd/compile/internal/gc/noder.go
+++ b/src/cmd/compile/internal/gc/noder.go
@@ -5,25 +5,28 @@
package gc
import (
- "cmd/compile/internal/syntax"
- "cmd/internal/src"
"fmt"
"os"
"strconv"
"strings"
"unicode/utf8"
+
+ "cmd/compile/internal/syntax"
+ "cmd/internal/obj"
+ "cmd/internal/src"
)
-func parseFile(filename string) {
- src, err := os.Open(filename)
+func parseFile(filename string) uint {
+ f, err := os.Open(filename)
if err != nil {
fmt.Println(err)
errorexit()
}
- defer src.Close()
+ defer f.Close()
- p := noder{baseline: lexlineno.Line()}
- file, _ := syntax.Parse(filename, src, p.error, p.pragma, 0) // errors are tracked via p.error
+ base := src.NewFileBase(filename, absFilename(filename))
+ var p noder
+ file, _ := syntax.Parse(base, f, p.error, p.pragma, 0) // errors are tracked via p.error
p.file(file)
@@ -36,12 +39,19 @@ func parseFile(filename string) {
if nsyntaxerrors == 0 {
testdclstack()
}
+
+ return file.Lines
+}
+
+var pathPrefix string
+
+func absFilename(name string) string {
+ return obj.AbsFile(Ctxt.Pathname, name, pathPrefix)
}
// noder transforms package syntax's AST into a Nod tree.
type noder struct {
- baseline int32
- linknames []syntax.Pos // tracks //go:linkname positions
+ linknames []src.Pos // tracks //go:linkname positions
}
func (p *noder) file(file *syntax.File) {
@@ -50,8 +60,16 @@ func (p *noder) file(file *syntax.File) {
xtop = append(xtop, p.decls(file.DeclList)...)
- lexlineno = src.MakePos(p.baseline + int32(file.Lines) - 1)
- lineno = lexlineno
+ // For compatibility with old code only (comparisons w/ toolstash):
+ // The old line number tracking simply continued incrementing the
+ // virtual line number (lexlineno) and using it also for lineno.
+ // After processing the last function, the lineno was used for the
+ // line number information of the initialization code (fninit).
+ // It would be better to use an explicit "<autogenerated>" filename
+ // for fninit and set lineno to NoPos here.
+ // TODO(gri) fix this once we switched permanently to the new
+ // position information.
+ lineno = src.MakePos(file.Pos().Base(), uint(file.Lines), 0)
}
func (p *noder) decls(decls []syntax.Decl) (l []*Node) {
@@ -231,7 +249,7 @@ func (p *noder) funcDecl(fun *syntax.FuncDecl) *Node {
yyerror("can only use //go:noescape with external func implementations")
}
f.Func.Pragma = pragma
- lineno = src.MakePos(p.baseline + int32(fun.EndLine) - 1)
+ lineno = src.MakePos(fun.Pos().Base(), fun.EndLine, 0)
f.Func.Endlineno = lineno
funcbody(f)
@@ -357,14 +375,14 @@ func (p *noder) expr(expr syntax.Expr) *Node {
l[i] = p.wrapname(expr.ElemList[i], e)
}
n.List.Set(l)
- lineno = src.MakePos(p.baseline + int32(expr.EndLine) - 1)
+ lineno = src.MakePos(expr.Pos().Base(), expr.EndLine, 0)
return n
case *syntax.KeyValueExpr:
return p.nod(expr, OKEY, p.expr(expr.Key), p.wrapname(expr.Value, p.expr(expr.Value)))
case *syntax.FuncLit:
closurehdr(p.typeExpr(expr.Type))
body := p.stmts(expr.Body)
- lineno = src.MakePos(p.baseline + int32(expr.EndLine) - 1)
+ lineno = src.MakePos(expr.Pos().Base(), expr.EndLine, 0)
return p.setlineno(expr, closurebody(body))
case *syntax.ParenExpr:
return p.nod(expr, OPAREN, p.expr(expr.X), nil)
@@ -986,12 +1004,12 @@ func (p *noder) nod(orig syntax.Node, op Op, left, right *Node) *Node {
}
func (p *noder) setlineno(src_ syntax.Node, dst *Node) *Node {
- l := src_.Pos().Line()
- if l == 0 {
+ pos := src_.Pos()
+ if !pos.IsKnown() {
// TODO(mdempsky): Shouldn't happen. Fix package syntax.
return dst
}
- dst.Pos = src.MakePos(p.baseline + int32(l) - 1)
+ dst.Pos = pos
return dst
}
@@ -999,48 +1017,24 @@ func (p *noder) lineno(n syntax.Node) {
if n == nil {
return
}
- l := n.Pos().Line()
- if l == 0 {
+ pos := n.Pos()
+ if !pos.IsKnown() {
// TODO(mdempsky): Shouldn't happen. Fix package syntax.
return
}
- lineno = src.MakePos(p.baseline + int32(l) - 1)
+ lineno = pos
}
func (p *noder) error(err error) {
- line := p.baseline
- var msg string
- if err, ok := err.(syntax.Error); ok {
- line += int32(err.Pos.Line()) - 1
- msg = err.Msg
- } else {
- msg = err.Error()
- }
- yyerrorl(src.MakePos(line), "%s", msg)
+ e := err.(syntax.Error)
+ yyerrorl(e.Pos, "%s", e.Msg)
}
-func (p *noder) pragma(pos syntax.Pos, text string) syntax.Pragma {
+func (p *noder) pragma(pos src.Pos, text string) syntax.Pragma {
switch {
case strings.HasPrefix(text, "line "):
- // Want to use LastIndexByte below but it's not defined in Go1.4 and bootstrap fails.
- i := strings.LastIndex(text, ":") // look from right (Windows filenames may contain ':')
- if i < 0 {
- break
- }
- n, err := strconv.Atoi(text[i+1:])
- if err != nil {
- // TODO: make this an error instead? it is almost certainly a bug.
- break
- }
- if n > 1e8 {
- p.error(syntax.Error{Pos: pos, Msg: "line number out of range"})
- errorexit()
- }
- if n <= 0 {
- break
- }
- lexlineno = src.MakePos(p.baseline + int32(pos.Line()))
- linehistupdate(text[5:i], n)
+ // line directives are handled by syntax package
+ panic("unreachable")
case strings.HasPrefix(text, "go:linkname "):
// Record line number so we can emit an error later if
diff --git a/src/cmd/compile/internal/gc/sizeof_test.go b/src/cmd/compile/internal/gc/sizeof_test.go
index b86188c314..d8964fd1d0 100644
--- a/src/cmd/compile/internal/gc/sizeof_test.go
+++ b/src/cmd/compile/internal/gc/sizeof_test.go
@@ -22,14 +22,14 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
- {Func{}, 92, 160},
+ {Func{}, 100, 184},
{Name{}, 44, 72},
{Param{}, 24, 48},
- {Node{}, 92, 144},
- {Sym{}, 60, 112},
- {Type{}, 60, 96},
+ {Node{}, 96, 160},
+ {Sym{}, 64, 128},
+ {Type{}, 64, 112},
{MapType{}, 20, 40},
- {ForwardType{}, 16, 32},
+ {ForwardType{}, 20, 40},
{FuncType{}, 28, 48},
{StructType{}, 12, 24},
{InterType{}, 4, 8},
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index a6a8deadc3..4cdc869606 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -282,8 +282,8 @@ func (s *state) label(sym *Sym) *ssaLabel {
func (s *state) Logf(msg string, args ...interface{}) { s.config.Logf(msg, args...) }
func (s *state) Log() bool { return s.config.Log() }
func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(s.peekPos(), msg, args...) }
-func (s *state) Warnl(line src.Pos, msg string, args ...interface{}) {
- s.config.Warnl(line, msg, args...)
+func (s *state) Warnl(pos src.Pos, msg string, args ...interface{}) {
+ s.config.Warnl(pos, msg, args...)
}
func (s *state) Debug_checknil() bool { return s.config.Debug_checknil() }
@@ -4462,8 +4462,11 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
f.Logf("%s\t%s\n", s, p)
}
if f.Config.HTML != nil {
- saved := ptxt.Ctxt.LineHist.PrintFilenameOnly
- ptxt.Ctxt.LineHist.PrintFilenameOnly = true
+ // LineHist is defunct now - this code won't do
+ // anything.
+ // TODO: fix this (ideally without a global variable)
+ // saved := ptxt.Ctxt.LineHist.PrintFilenameOnly
+ // ptxt.Ctxt.LineHist.PrintFilenameOnly = true
var buf bytes.Buffer
buf.WriteString("<code>")
buf.WriteString("<dl class=\"ssa-gen\">")
@@ -4483,7 +4486,7 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
buf.WriteString("</dl>")
buf.WriteString("</code>")
f.Config.HTML.WriteColumn("genssa", buf.String())
- ptxt.Ctxt.LineHist.PrintFilenameOnly = saved
+ // ptxt.Ctxt.LineHist.PrintFilenameOnly = saved
}
}
@@ -4958,8 +4961,8 @@ func (e *ssaExport) CanSSA(t ssa.Type) bool {
return canSSAType(t.(*Type))
}
-func (e *ssaExport) Line(line src.Pos) string {
- return linestr(line)
+func (e *ssaExport) Line(pos src.Pos) string {
+ return linestr(pos)
}
// Log logs a message from the compiler.
@@ -4974,15 +4977,15 @@ func (e *ssaExport) Log() bool {
}
// Fatal reports a compiler error and exits.
-func (e *ssaExport) Fatalf(line src.Pos, msg string, args ...interface{}) {
- lineno = line
+func (e *ssaExport) Fatalf(pos src.Pos, msg string, args ...interface{}) {
+ lineno = pos
Fatalf(msg, args...)
}
// Warnl reports a "warning", which is usually flag-triggered
// logging output for the benefit of tests.
-func (e *ssaExport) Warnl(line src.Pos, fmt_ string, args ...interface{}) {
- Warnl(line, fmt_, args...)
+func (e *ssaExport) Warnl(pos src.Pos, fmt_ string, args ...interface{}) {
+ Warnl(pos, fmt_, args...)
}
func (e *ssaExport) Debug_checknil() bool {
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index 6d3d9688d4..44a1ab479b 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -86,49 +86,54 @@ func hcrash() {
}
}
-func linestr(line src.Pos) string {
- return Ctxt.Line(int(line.Line()))
+func linestr(pos src.Pos) string {
+ return pos.String()
}
// lasterror keeps track of the most recently issued error.
// It is used to avoid multiple error messages on the same
// line.
var lasterror struct {
- syntax src.Pos // line of last syntax error
- other src.Pos // line of last non-syntax error
+ syntax src.Pos // source position of last syntax error
+ other src.Pos // source position of last non-syntax error
msg string // error message of last non-syntax error
}
-func yyerrorl(line src.Pos, format string, args ...interface{}) {
+// sameline reports whether two positions a, b are on the same line.
+func sameline(a, b src.Pos) bool {
+ return a.Filename() == b.Filename() && a.Line() == b.Line()
+}
+
+func yyerrorl(pos src.Pos, format string, args ...interface{}) {
msg := fmt.Sprintf(format, args...)
if strings.HasPrefix(msg, "syntax error") {
nsyntaxerrors++
// only one syntax error per line, no matter what error
- if lasterror.syntax == line {
+ if sameline(lasterror.syntax, pos) {
return
}
- lasterror.syntax = line
+ lasterror.syntax = pos
} else {
// only one of multiple equal non-syntax errors per line
// (flusherrors shows only one of them, so we filter them
// here as best as we can (they may not appear in order)
// so that we don't count them here and exit early, and
// then have nothing to show for.)
- if lasterror.other == line && lasterror.msg == msg {
+ if sameline(lasterror.other, pos) && lasterror.msg == msg {
return
}
- lasterror.other = line
+ lasterror.other = pos
lasterror.msg = msg
}
- adderr(line, "%s", msg)
+ adderr(pos, "%s", msg)
hcrash()
nerrors++
if nsavederrors+nerrors >= 10 && Debug['e'] == 0 {
flusherrors()
- fmt.Printf("%v: too many errors\n", linestr(line))
+ fmt.Printf("%v: too many errors\n", linestr(pos))
errorexit()
}
}
@@ -173,34 +178,14 @@ func Fatalf(fmt_ string, args ...interface{}) {
errorexit()
}
+// TODO(gri) rename this function
func linehistpragma(file string) {
- if Debug['i'] != 0 {
- fmt.Printf("pragma %s at line %v\n", file, linestr(lexlineno))
- }
+ // if Debug['i'] != 0 {
+ // fmt.Printf("pragma %s at line %v\n", file, linestr(lexlineno))
+ // }
Ctxt.AddImport(file)
}
-func linehistpush(file string) {
- if Debug['i'] != 0 {
- fmt.Printf("import %s at line %v\n", file, linestr(lexlineno))
- }
- Ctxt.LineHist.Push(int(lexlineno.Line()), file)
-}
-
-func linehistpop() {
- if Debug['i'] != 0 {
- fmt.Printf("end of import at line %v\n", linestr(lexlineno))
- }
- Ctxt.LineHist.Pop(int(lexlineno.Line()))
-}
-
-func linehistupdate(file string, off int) {
- if Debug['i'] != 0 {
- fmt.Printf("line %s at line %v\n", file, linestr(lexlineno))
- }
- Ctxt.LineHist.Update(int(lexlineno.Line()), file, off)
-}
-
func setlineno(n *Node) src.Pos {
lno := lineno
if n != nil {
@@ -474,9 +459,9 @@ func nodbool(b bool) *Node {
// treecopy recursively copies n, with the exception of
// ONAME, OLITERAL, OTYPE, and non-iota ONONAME leaves.
// Copies of iota ONONAME nodes are assigned the current
-// value of iota_. If lineno != 0, it sets the line number
-// of newly allocated nodes to lineno.
-func treecopy(n *Node, lineno src.Pos) *Node {
+// value of iota_. If pos.IsKnown(), it sets the source
+// position of newly allocated nodes to pos.
+func treecopy(n *Node, pos src.Pos) *Node {
if n == nil {
return nil
}
@@ -485,11 +470,11 @@ func treecopy(n *Node, lineno src.Pos) *Node {
default:
m := *n
m.Orig = &m
- m.Left = treecopy(n.Left, lineno)
- m.Right = treecopy(n.Right, lineno)
- m.List.Set(listtreecopy(n.List.Slice(), lineno))
- if lineno.IsKnown() {
- m.Pos = lineno
+ m.Left = treecopy(n.Left, pos)
+ m.Right = treecopy(n.Right, pos)
+ m.List.Set(listtreecopy(n.List.Slice(), pos))
+ if pos.IsKnown() {
+ m.Pos = pos
}
if m.Name != nil && n.Op != ODCLFIELD {
Dump("treecopy", n)
@@ -504,8 +489,8 @@ func treecopy(n *Node, lineno src.Pos) *Node {
// so that all the copies of this const definition
// don't have the same iota value.
m := *n
- if lineno.IsKnown() {
- m.Pos = lineno
+ if pos.IsKnown() {
+ m.Pos = pos
}
m.SetIota(iota_)
return &m
@@ -1707,21 +1692,12 @@ func structargs(tl *Type, mustname bool) []*Node {
// method - M func (t T)(), a TFIELD type struct
// newnam - the eventual mangled name of this function
-var genwrapper_linehistdone int = 0
-
func genwrapper(rcvr *Type, method *Field, newnam *Sym, iface int) {
if false && Debug['r'] != 0 {
fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
}
- lexlineno = src.MakePos(lexlineno.Line() + 1)
- lineno = lexlineno
- if genwrapper_linehistdone == 0 {
- // All the wrappers can share the same linehist entry.
- linehistpush("<autogenerated>")
-
- genwrapper_linehistdone = 1
- }
+ lineno = src.MakePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
dclcontext = PEXTERN
markdcl()
@@ -1992,10 +1968,10 @@ func Simsimtype(t *Type) EType {
return et
}
-func listtreecopy(l []*Node, lineno src.Pos) []*Node {
+func listtreecopy(l []*Node, pos src.Pos) []*Node {
var out []*Node
for _, n := range l {
- out = append(out, treecopy(n, lineno))
+ out = append(out, treecopy(n, pos))
}
return out
}
diff --git a/src/cmd/compile/internal/gc/util.go b/src/cmd/compile/internal/gc/util.go
index 7f1d26d370..cfc63738d6 100644
--- a/src/cmd/compile/internal/gc/util.go
+++ b/src/cmd/compile/internal/gc/util.go
@@ -11,7 +11,7 @@ import (
)
func (n *Node) Line() string {
- return Ctxt.LineHist.LineString(int(n.Pos.Line()))
+ return linestr(n.Pos)
}
var atExitFuncs []func()
diff --git a/src/cmd/compile/internal/ssa/sizeof_test.go b/src/cmd/compile/internal/ssa/sizeof_test.go
index 4aab923653..7792318e20 100644
--- a/src/cmd/compile/internal/ssa/sizeof_test.go
+++ b/src/cmd/compile/internal/ssa/sizeof_test.go
@@ -22,8 +22,8 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
- {Value{}, 68, 112},
- {Block{}, 148, 288},
+ {Value{}, 72, 128},
+ {Block{}, 152, 304},
}
for _, tt := range tests {
diff --git a/src/cmd/compile/internal/syntax/dumper_test.go b/src/cmd/compile/internal/syntax/dumper_test.go
index 2b20cbdd97..1186193aba 100644
--- a/src/cmd/compile/internal/syntax/dumper_test.go
+++ b/src/cmd/compile/internal/syntax/dumper_test.go
@@ -14,7 +14,7 @@ func TestDump(t *testing.T) {
t.Skip("skipping test in short mode")
}
- ast, err := ParseFile(*src, nil, nil, 0)
+ ast, err := ParseFile(*src_, nil, nil, 0)
if err != nil {
t.Fatal(err)
}
diff --git a/src/cmd/compile/internal/syntax/nodes.go b/src/cmd/compile/internal/syntax/nodes.go
index adbb4da750..82c6c1907f 100644
--- a/src/cmd/compile/internal/syntax/nodes.go
+++ b/src/cmd/compile/internal/syntax/nodes.go
@@ -4,11 +4,13 @@
package syntax
+import "cmd/internal/src"
+
// ----------------------------------------------------------------------------
// Nodes
type Node interface {
- Pos() Pos
+ Pos() src.Pos
aNode()
init(p *parser)
}
@@ -16,10 +18,10 @@ type Node interface {
type node struct {
// commented out for now since not yet used
// doc *Comment // nil means no comment(s) attached
- pos Pos
+ pos src.Pos
}
-func (n *node) Pos() Pos {
+func (n *node) Pos() src.Pos {
return n.pos
}
diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go
index eb9c3e4aa5..e70ac3d714 100644
--- a/src/cmd/compile/internal/syntax/parser.go
+++ b/src/cmd/compile/internal/syntax/parser.go
@@ -5,6 +5,7 @@
package syntax
import (
+ "cmd/internal/src"
"fmt"
"io"
"strconv"
@@ -20,7 +21,7 @@ const trace = false
const gcCompat = true
type parser struct {
- base *PosBase
+ base *src.PosBase
errh ErrorHandler
scanner
@@ -32,11 +33,11 @@ type parser struct {
indent []byte // tracing support
}
-func (p *parser) init(filename string, src io.Reader, errh ErrorHandler, pragh PragmaHandler) {
- p.base = NewFileBase(filename)
+func (p *parser) init(base *src.PosBase, r io.Reader, errh ErrorHandler, pragh PragmaHandler) {
+ p.base = base
p.errh = errh
p.scanner.init(
- src,
+ r,
// Error and pragma handlers for scanner.
// Because the (line, col) positions passed to these
// handlers are always at or after the current reading
@@ -48,6 +49,7 @@ func (p *parser) init(filename string, src io.Reader, errh ErrorHandler, pragh P
func(line, col uint, text string) {
if strings.HasPrefix(text, "line ") {
p.updateBase(line, col+5, text[5:])
+ return
}
if pragh != nil {
p.pragma |= pragh(p.pos_at(line, col), text)
@@ -63,6 +65,8 @@ func (p *parser) init(filename string, src 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) {
// Want to use LastIndexByte below but it's not defined in Go1.4 and bootstrap fails.
i := strings.LastIndex(text, ":") // look from right (Windows filenames may contain ':')
@@ -75,7 +79,7 @@ func (p *parser) updateBase(line, col uint, text string) {
p.error_at(p.pos_at(line, col+uint(i+1)), "invalid line number: "+nstr)
return
}
- p.base = NewLinePragmaBase(MakePos(p.base.Pos().Base(), line, col), text[:i], uint(n))
+ p.base = src.NewLinePragmaBase(src.MakePos(p.base.Pos().Base(), line, col), text[:i], uint(n))
}
func (p *parser) got(tok token) bool {
@@ -97,12 +101,12 @@ func (p *parser) want(tok token) {
// Error handling
// pos_at returns the Pos value for (line, col) and the current position base.
-func (p *parser) pos_at(line, col uint) Pos {
- return MakePos(p.base, line, col)
+func (p *parser) pos_at(line, col uint) src.Pos {
+ return src.MakePos(p.base, line, col)
}
// error reports an error at the given position.
-func (p *parser) error_at(pos Pos, msg string) {
+func (p *parser) error_at(pos src.Pos, msg string) {
err := Error{pos, msg}
if p.first == nil {
p.first = err
@@ -114,7 +118,7 @@ func (p *parser) error_at(pos Pos, msg string) {
}
// syntax_error_at reports a syntax error at the given position.
-func (p *parser) syntax_error_at(pos Pos, msg string) {
+func (p *parser) syntax_error_at(pos src.Pos, msg string) {
if trace {
defer p.trace("syntax_error (" + msg + ")")()
}
@@ -159,7 +163,7 @@ func (p *parser) syntax_error_at(pos Pos, msg string) {
}
// Convenience methods using the current token position.
-func (p *parser) pos() Pos { return p.pos_at(p.line, p.col) }
+func (p *parser) pos() src.Pos { return p.pos_at(p.line, p.col) }
func (p *parser) error(msg string) { p.error_at(p.pos(), msg) }
func (p *parser) syntax_error(msg string) { p.syntax_error_at(p.pos(), msg) }
diff --git a/src/cmd/compile/internal/syntax/parser_test.go b/src/cmd/compile/internal/syntax/parser_test.go
index 23fed3b105..da56168957 100644
--- a/src/cmd/compile/internal/syntax/parser_test.go
+++ b/src/cmd/compile/internal/syntax/parser_test.go
@@ -6,6 +6,7 @@ package syntax
import (
"bytes"
+ "cmd/internal/src"
"flag"
"fmt"
"io/ioutil"
@@ -18,11 +19,11 @@ import (
)
var fast = flag.Bool("fast", false, "parse package files in parallel")
-var src = flag.String("src", "parser.go", "source file to parse")
+var src_ = flag.String("src", "parser.go", "source file to parse")
var verify = flag.Bool("verify", false, "verify idempotent printing")
func TestParse(t *testing.T) {
- _, err := ParseFile(*src, nil, nil, 0)
+ _, err := ParseFile(*src_, nil, nil, 0)
if err != nil {
t.Fatal(err)
}
@@ -133,7 +134,7 @@ func verifyPrint(filename string, ast1 *File) {
panic(err)
}
- ast2, err := ParseBytes(filename, buf1.Bytes(), nil, nil, 0)
+ ast2, err := ParseBytes(src.NewFileBase(filename, filename), buf1.Bytes(), nil, nil, 0)
if err != nil {
panic(err)
}
@@ -157,7 +158,7 @@ func verifyPrint(filename string, ast1 *File) {
}
func TestIssue17697(t *testing.T) {
- _, err := ParseBytes("", nil, nil, nil, 0) // return with parser error, don't panic
+ _, err := ParseBytes(nil, nil, nil, nil, 0) // return with parser error, don't panic
if err == nil {
t.Errorf("no error reported")
}
@@ -202,7 +203,7 @@ func TestLineDirectives(t *testing.T) {
{"//line foo:123\n foo", "syntax error: package statement must be first", "foo", 123, 3},
{"//line foo:123\n//line bar:345\nfoo", "syntax error: package statement must be first", "bar", 345, 0},
} {
- _, err := ParseBytes("", []byte(test.src), nil, nil, 0)
+ _, err := ParseBytes(nil, []byte(test.src), nil, nil, 0)
if err == nil {
t.Errorf("%s: no error reported", test.src)
continue
diff --git a/src/cmd/compile/internal/syntax/pos.go b/src/cmd/compile/internal/syntax/pos.go
deleted file mode 100644
index 98cdae9327..0000000000
--- a/src/cmd/compile/internal/syntax/pos.go
+++ /dev/null
@@ -1,180 +0,0 @@
-// Copyright 2016 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.
-
-// This file implements the encoding of source positions.
-
-package syntax
-
-import "strconv"
-
-// A Pos encodes a source position consisting of a (line, column) number pair
-// and a position base. A zero Pos is a ready to use "unknown" position (nil
-// position base and zero line number).
-//
-// The (line, column) values refer to a position in a file independent of any
-// position base ("absolute" position). Line numbers start at 1, column values
-// start at 0 and are byte offsets from the beginning of the line.
-//
-// The position base is used to determine the "relative" position, that is the
-// filename and line number relative to the position base. If the base refers
-// to the current file, there is no difference between absolute and relative
-// positions. If it refers to a //line pragma, a relative position is relative
-// to that pragma. A position base in turn contains the position at which it
-// was introduced in the current file.
-type Pos struct {
- base *PosBase
- lico
-}
-
-// NoPos is a valid unknown position.
-var NoPos Pos
-
-// MakePos creates a new Pos value with the given base, and (file-absolute)
-// line and column.
-func MakePos(base *PosBase, line, col uint) Pos {
- return Pos{base, makeLico(line, col)}
-}
-
-// IsKnown reports whether the position p is known.
-func (p Pos) IsKnown() bool {
- return p.base != nil || p.Line() != 0
-}
-
-// Before reports whether the position p comes before q in the source.
-// For positions in different files, ordering is by filename.
-func (p Pos) Before(q Pos) bool {
- n, m := p.Filename(), q.Filename()
- return n < m || n == m && p.lico < q.lico
-}
-
-// After reports whether the position p comes after q in the source.
-// For positions in different files, ordering is by filename.
-func (p Pos) After(q Pos) bool {
- n, m := p.Filename(), q.Filename()
- return n > m || n == m && p.lico > q.lico
-}
-
-// Filename returns the name of the actual file containing this position.
-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 { return p.base.Filename() }
-
-// RelLine returns the line number relative to the positions's base.
-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 == b.Pos().base {
- // base is file base (incl. nil)
- return posString(b.Filename(), p.Line(), p.Col())
- }
-
- // base is relative
- 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)
- // col == colMax is interpreted as unknown column value
- if col < colMax {
- s += ":" + strconv.FormatUint(uint64(col), 10)
- }
- return s
-}
-
-// ----------------------------------------------------------------------------
-// PosBase
-
-// A PosBase encodes a filename and base line number.
-// Typically, each file and line pragma introduce a PosBase.
-// A nil *PosBase is a ready to use file PosBase for an unnamed
-// file with line numbers starting at 1.
-type PosBase struct {
- pos Pos
- filename string
- line uint
-}
-
-// NewFileBase returns a new *PosBase for a file with the given filename.
-func NewFileBase(filename string) *PosBase {
- 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
-// //line filename:line
-// at position pos.
-func NewLinePragmaBase(pos Pos, filename string, line uint) *PosBase {
- return &PosBase{pos, filename, line - 1}
-}
-
-var noPos Pos
-
-// Pos returns the position at which base is located.
-// If b == nil, the result is the zero position.
-func (b *PosBase) Pos() *Pos {
- if b != nil {
- return &b.pos
- }
- return &noPos
-}
-
-// Filename returns the filename recorded with the base.
-// If b == nil, the result is the empty string.
-func (b *PosBase) Filename() string {
- if b != nil {
- return b.filename
- }
- return ""
-}
-
-// Line returns the line number recorded with the base.
-// If b == nil, the result is 0.
-func (b *PosBase) Line() uint {
- if b != nil {
- return b.line
- }
- return 0
-}
-
-// ----------------------------------------------------------------------------
-// lico
-
-// A lico is a compact encoding of a LIne and COlumn number.
-type lico uint32
-
-// Layout constants: 24 bits for line, 8 bits for column.
-// (If this is too tight, we can either make lico 64b wide,
-// or we can introduce a tiered encoding where we remove column
-// information as line numbers grow bigger; similar to what gcc
-// does.)
-const (
- lineBits, lineMax = 24, 1<<lineBits - 1
- colBits, colMax = 32 - lineBits, 1<<colBits - 1
-)
-
-func makeLico(line, col uint) lico {
- if line > lineMax {
- // cannot represent line, use max. line so we have some information
- line = lineMax
- }
- if col > colMax {
- // cannot represent column, use max. column so we have some information
- col = colMax
- }
- return lico(line<<colBits | 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
deleted file mode 100644
index bf2a0c1dfa..0000000000
--- a/src/cmd/compile/internal/syntax/pos_test.go
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright 2016 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"
- "testing"
-)
-
-func TestPos(t *testing.T) {
- f0 := NewFileBase("")
- f1 := NewFileBase("f1")
- f2 := NewLinePragmaBase(Pos{}, "f2", 10)
- f3 := NewLinePragmaBase(MakePos(f1, 10, 1), "f3", 100)
- f4 := NewLinePragmaBase(MakePos(f3, 10, 1), "f4", 100)
-
- for _, test := range []struct {
- pos Pos
- string string
-
- // absolute info
- filename string
- line, col uint
-
- // relative info
- relFilename string
- relLine uint
- }{
- {Pos{}, ":0: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: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
- } {
- pos := test.pos
- if got := pos.String(); got != test.string {
- t.Errorf("%s: got %q", test.string, got)
- }
-
- // absolute info
- if got := pos.Filename(); got != test.filename {
- t.Errorf("%s: got filename %q; want %q", test.string, got, test.filename)
- }
- if got := pos.Line(); got != test.line {
- t.Errorf("%s: got line %d; want %d", test.string, got, test.line)
- }
- if got := pos.Col(); got != test.col {
- t.Errorf("%s: got col %d; want %d", test.string, got, test.col)
- }
-
- // relative info
- if got := pos.RelFilename(); got != test.relFilename {
- t.Errorf("%s: got relFilename %q; want %q", test.string, got, test.relFilename)
- }
- if got := pos.RelLine(); got != test.relLine {
- t.Errorf("%s: got relLine %d; want %d", test.string, got, test.relLine)
- }
- }
-}
-
-func TestPredicates(t *testing.T) {
- b1 := NewFileBase("b1")
- b2 := NewFileBase("b2")
- for _, test := range []struct {
- p, q Pos
- known, before, after bool
- }{
- {NoPos, NoPos, false, false, false},
- {NoPos, MakePos(nil, 1, 0), false, true, false},
- {MakePos(b1, 0, 0), NoPos, true, false, true},
- {MakePos(nil, 1, 0), NoPos, true, false, true},
-
- {MakePos(nil, 1, 1), MakePos(nil, 1, 1), true, false, false},
- {MakePos(nil, 1, 1), MakePos(nil, 1, 2), true, true, false},
- {MakePos(nil, 1, 2), MakePos(nil, 1, 1), true, false, true},
- {MakePos(nil, 123, 1), MakePos(nil, 1, 123), true, false, true},
-
- {MakePos(b1, 1, 1), MakePos(b1, 1, 1), true, false, false},
- {MakePos(b1, 1, 1), MakePos(b1, 1, 2), true, true, false},
- {MakePos(b1, 1, 2), MakePos(b1, 1, 1), true, false, true},
- {MakePos(b1, 123, 1), MakePos(b1, 1, 123), true, false, true},
-
- {MakePos(b1, 1, 1), MakePos(b2, 1, 1), true, true, false},
- {MakePos(b1, 1, 1), MakePos(b2, 1, 2), true, true, false},
- {MakePos(b1, 1, 2), MakePos(b2, 1, 1), true, true, false},
- {MakePos(b1, 123, 1), MakePos(b2, 1, 123), true, true, false},
-
- // special case: unknown column (column too large to represent)
- {MakePos(nil, 1, colMax+10), MakePos(nil, 1, colMax+20), true, false, false},
- } {
- if got := test.p.IsKnown(); got != test.known {
- t.Errorf("%s known: got %v; want %v", test.p, got, test.known)
- }
- if got := test.p.Before(test.q); got != test.before {
- t.Errorf("%s < %s: got %v; want %v", test.p, test.q, got, test.before)
- }
- if got := test.p.After(test.q); got != test.after {
- t.Errorf("%s > %s: got %v; want %v", test.p, test.q, got, test.after)
- }
- }
-}
-
-func TestLico(t *testing.T) {
- for _, test := range []struct {
- x lico
- string string
- line, col uint
- }{
- {0, ":0:0", 0, 0},
- {makeLico(0, 0), ":0:0", 0, 0},
- {makeLico(0, 1), ":0:1", 0, 1},
- {makeLico(1, 0), ":1:0", 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), ":1", 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 := posString("", x.Line(), x.Col()); got != test.string {
- t.Errorf("%s: got %q", test.string, got)
- }
- }
-}
diff --git a/src/cmd/compile/internal/syntax/printer_test.go b/src/cmd/compile/internal/syntax/printer_test.go
index 5c0fc776a1..dc9a32b6d3 100644
--- a/src/cmd/compile/internal/syntax/printer_test.go
+++ b/src/cmd/compile/internal/syntax/printer_test.go
@@ -15,7 +15,7 @@ func TestPrint(t *testing.T) {
t.Skip("skipping test in short mode")
}
- ast, err := ParseFile(*src, nil, nil, 0)
+ ast, err := ParseFile(*src_, nil, nil, 0)
if err != nil {
t.Fatal(err)
}
diff --git a/src/cmd/compile/internal/syntax/syntax.go b/src/cmd/compile/internal/syntax/syntax.go
index 4585defb8f..db2bcb4a0c 100644
--- a/src/cmd/compile/internal/syntax/syntax.go
+++ b/src/cmd/compile/internal/syntax/syntax.go
@@ -5,6 +5,7 @@
package syntax
import (
+ "cmd/internal/src"
"fmt"
"io"
"os"
@@ -15,7 +16,7 @@ type Mode uint
// Error describes a syntax error. Error implements the error interface.
type Error struct {
- Pos Pos
+ Pos src.Pos
Msg string
}
@@ -36,11 +37,11 @@ type Pragma uint16
// A PragmaHandler is used to process //line and //go: directives as
// they're scanned. The returned Pragma value will be unioned into the
// next FuncDecl node.
-type PragmaHandler func(pos Pos, text string) Pragma
+type PragmaHandler func(pos src.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.
-// The filename is only used for position information.
+// The base argument is only used for position information.
//
// If errh != nil, it is called with each error encountered, and Parse will
// process as much source as possible. If errh is nil, Parse will terminate
@@ -49,7 +50,7 @@ type PragmaHandler func(pos Pos, text string) Pragma
// If a PragmaHandler is provided, it is called with each pragma encountered.
//
// The Mode argument is currently ignored.
-func Parse(filename string, src io.Reader, errh ErrorHandler, pragh PragmaHandler, mode Mode) (_ *File, first error) {
+func Parse(base *src.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 {
@@ -61,14 +62,14 @@ func Parse(filename string, src io.Reader, errh ErrorHandler, pragh PragmaHandle
}()
var p parser
- p.init(filename, src, errh, pragh)
+ p.init(base, src, errh, pragh)
p.next()
return p.file(), p.first
}
// ParseBytes behaves like Parse but it reads the source from the []byte slice provided.
-func ParseBytes(filename string, src []byte, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) {
- return Parse(filename, &bytesReader{src}, errh, pragh, mode)
+func ParseBytes(base *src.PosBase, src []byte, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) {
+ return Parse(base, &bytesReader{src}, errh, pragh, mode)
}
type bytesReader struct {
@@ -86,13 +87,13 @@ func (r *bytesReader) Read(p []byte) (int, error) {
// ParseFile behaves like Parse but it reads the source from the named file.
func ParseFile(filename string, errh ErrorHandler, pragh PragmaHandler, mode Mode) (*File, error) {
- src, err := os.Open(filename)
+ f, err := os.Open(filename)
if err != nil {
if errh != nil {
errh(err)
}
return nil, err
}
- defer src.Close()
- return Parse(filename, src, errh, pragh, mode)
+ defer f.Close()
+ return Parse(src.NewFileBase(filename, filename), f, errh, pragh, mode)
}