import (
"bytes"
"cmd/internal/obj"
+ "cmd/internal/src"
"crypto/md5"
"encoding/binary"
"fmt"
)
type Error struct {
- lineno int32
- msg string
+ pos src.XPos
+ msg string
}
var errors []Error
return
}
old := fmt.Sprintf("%v: undefined: %v\n", n.Line(), n.Left)
- if len(errors) > 0 && errors[len(errors)-1].lineno == n.Lineno && errors[len(errors)-1].msg == old {
+ if len(errors) > 0 && errors[len(errors)-1].pos.Line() == n.Pos.Line() && errors[len(errors)-1].msg == old {
errors[len(errors)-1].msg = fmt.Sprintf("%v: undefined: %v in %v\n", n.Line(), n.Left, n)
}
}
-func adderr(line int32, format string, args ...interface{}) {
+func adderr(pos src.XPos, format string, args ...interface{}) {
errors = append(errors, Error{
- lineno: line,
- msg: fmt.Sprintf("%v: %s\n", linestr(line), fmt.Sprintf(format, args...)),
+ pos: pos,
+ msg: fmt.Sprintf("%v: %s\n", linestr(pos), fmt.Sprintf(format, args...)),
})
}
-// byLineno sorts errors by lineno.
-type byLineno []Error
+// byPos sorts errors by source position.
+type byPos []Error
-func (x byLineno) Len() int { return len(x) }
-func (x byLineno) Less(i, j int) bool { return x[i].lineno < x[j].lineno }
-func (x byLineno) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
+func (x byPos) Len() int { return len(x) }
+func (x byPos) Less(i, j int) bool { return x[i].pos.Before(x[j].pos) }
+func (x byPos) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
// flusherrors sorts errors seen so far by line number, prints them to stdout,
// and empties the errors array.
if len(errors) == 0 {
return
}
- sort.Stable(byLineno(errors))
+ sort.Stable(byPos(errors))
for i := 0; i < len(errors); i++ {
if i == 0 || errors[i].msg != errors[i-1].msg {
fmt.Printf("%s", errors[i].msg)
}
}
-func linestr(line int32) string {
- return Ctxt.Line(int(line))
+func linestr(pos src.XPos) string {
+ return Ctxt.PosTable.Pos(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 int32 // line of last syntax error
- other int32 // line of last non-syntax error
- msg string // error message of last non-syntax error
+ syntax src.XPos // source position of last syntax error
+ other src.XPos // source position of last non-syntax error
+ msg string // error message of last non-syntax error
}
-func yyerrorl(line int32, format string, args ...interface{}) {
+// sameline reports whether two positions a, b are on the same line.
+func sameline(a, b src.XPos) bool {
+ p := Ctxt.PosTable.Pos(a)
+ q := Ctxt.PosTable.Pos(b)
+ return p.Base() == q.Base() && p.Line() == q.Line()
+}
+
+func yyerrorl(pos src.XPos, 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()
}
}
hcrash()
}
-func Warnl(line int32, fmt_ string, args ...interface{}) {
+func Warnl(line src.XPos, fmt_ string, args ...interface{}) {
adderr(line, fmt_, args...)
if Debug['m'] != 0 {
flusherrors()
errorexit()
}
-func linehistpragma(file string) {
- 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), file)
-}
-
-func linehistpop() {
- if Debug['i'] != 0 {
- fmt.Printf("end of import at line %v\n", linestr(lexlineno))
- }
- Ctxt.LineHist.Pop(int(lexlineno))
-}
-
-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), file, off)
-}
-
-func setlineno(n *Node) int32 {
+func setlineno(n *Node) src.XPos {
lno := lineno
if n != nil {
switch n.Op {
fallthrough
default:
- lineno = n.Lineno
- if lineno == 0 {
+ lineno = n.Pos
+ if !lineno.IsKnown() {
if Debug['K'] != 0 {
- Warn("setlineno: line 0")
+ Warn("setlineno: unknown position (line 0)")
}
lineno = lno
}
if n == 0 {
// can't possibly be used - there were no symbols
- yyerrorl(pack.Lineno, "imported and not used: %q", opkg.Path)
+ yyerrorl(pack.Pos, "imported and not used: %q", opkg.Path)
}
}
n.Op = op
n.Left = nleft
n.Right = nright
- n.Lineno = lineno
+ n.Pos = lineno
n.Xoffset = BADWIDTH
n.Orig = n
switch op {
// 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 int32) *Node {
+// value of iota_. If pos.IsKnown(), it sets the source
+// position of newly allocated nodes to pos.
+func treecopy(n *Node, pos src.XPos) *Node {
if n == nil {
return nil
}
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 != 0 {
- m.Lineno = 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)
// so that all the copies of this const definition
// don't have the same iota value.
m := *n
- if lineno != 0 {
- m.Lineno = lineno
+ if pos.IsKnown() {
+ m.Pos = pos
}
m.SetIota(iota_)
return &m
// 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++
- lineno = lexlineno
- if genwrapper_linehistdone == 0 {
- // All the wrappers can share the same linehist entry.
- linehistpush("<autogenerated>")
-
- genwrapper_linehistdone = 1
- }
+ lineno = MakePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
dclcontext = PEXTERN
markdcl()
return et
}
-func listtreecopy(l []*Node, lineno int32) []*Node {
+func listtreecopy(l []*Node, pos src.XPos) []*Node {
var out []*Node
for _, n := range l {
- out = append(out, treecopy(n, lineno))
+ out = append(out, treecopy(n, pos))
}
return out
}
n := nod(OBLOCK, nil, nil)
n.List.Set(l)
if len(l) != 0 {
- n.Lineno = l[0].Lineno
+ n.Pos = l[0].Pos
}
return n
}