diff options
author | Robert Griesemer <gri@golang.org> | 2009-07-14 10:44:57 -0700 |
---|---|---|
committer | Robert Griesemer <gri@golang.org> | 2009-07-14 10:44:57 -0700 |
commit | b5318dcac20f5c1302975995b35f9883cf173cb0 (patch) | |
tree | 958b37c128124281cf2faae1191a55e15db02124 /src/pkg/go/scanner/errors.go | |
parent | af68bb2b309c186a519201f4c3bbcc339fdd064a (diff) | |
download | golang-b5318dcac20f5c1302975995b35f9883cf173cb0.tar.gz |
- added Filename field to token.Position
- handle //line filename:line comments in scanner
- moved error handling code used by various scanner clients
to errors.go
- added extra tests
R=rsc
DELTA=385 (343 added, 18 deleted, 24 changed)
OCL=31551
CL=31601
Diffstat (limited to 'src/pkg/go/scanner/errors.go')
-rw-r--r-- | src/pkg/go/scanner/errors.go | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/src/pkg/go/scanner/errors.go b/src/pkg/go/scanner/errors.go new file mode 100644 index 000000000..54770f020 --- /dev/null +++ b/src/pkg/go/scanner/errors.go @@ -0,0 +1,203 @@ +// Copyright 2009 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 scanner + +import ( + "container/vector"; + "fmt"; + "go/token"; + "io"; + "os"; + "sort"; +) + + +// An implementation of an ErrorHandler may be provided to the Scanner. +// If a syntax error is encountered and a handler was installed, Error +// is called with a position and an error message. The position points +// to the beginning of the offending token. +// +type ErrorHandler interface { + Error(pos token.Position, msg string); +} + + +// ErrorVector implements the ErrorHandler interface. It must be +// initialized with Init(). It maintains a list of errors which can +// be retrieved with GetErrorList and GetError. +// +// A common usage pattern is to embed an ErrorVector alongside a +// scanner in a data structure that uses the scanner. By passing a +// reference to an ErrorVector to the scanner's Init call, default +// error handling is obtained. +// +type ErrorVector struct { + errors vector.Vector; +} + + +// Init initializes an ErrorVector. +func (h *ErrorVector) Init() { + h.errors.Init(0); +} + + +// NewErrorVector creates a new ErrorVector. +func NewErrorVector() *ErrorVector { + h := new(ErrorVector); + h.Init(); + return h; +} + + +// ErrorCount returns the number of errors collected. +func (h *ErrorVector) ErrorCount() int { + return h.errors.Len(); +} + + +// Within ErrorVector, an error is represented by an Error node. The +// position Pos, if valid, points to the beginning of the offending +// token, and the error condition is described by Msg. +// +type Error struct { + Pos token.Position; + Msg string; +} + + +func (e *Error) String() string { + s := e.Pos.Filename; + if s != "" { + s += ":"; + } + if e.Pos.IsValid() { + s += fmt.Sprintf("%d:%d:", e.Pos.Line, e.Pos.Column); + } + if s != "" { + s += " "; + } + return s + e.Msg; +} + + +// An ErrorList is a (possibly sorted) list of Errors. +type ErrorList []*Error + + +// ErrorList implements the SortInterface. +func (p ErrorList) Len() int { return len(p); } +func (p ErrorList) Swap(i, j int) { p[i], p[j] = p[j], p[i]; } + + +func (p ErrorList) Less(i, j int) bool { + e := &p[i].Pos; + f := &p[j].Pos; + // Note that it is not sufficient to simply compare file offsets because + // the offsets do not reflect modified line information (through //line + // comments). + if e.Filename < f.Filename { + return true; + } + if e.Filename == f.Filename { + if e.Line < f.Line { + return true; + } + if e.Line == f.Line { + return e.Column < f.Column; + } + } + return false; +} + + +func (p ErrorList) String() string { + switch len(p) { + case 0: + return "unspecified error"; + case 1: + return p[0].String(); + } + return fmt.Sprintf("%s (and %d more errors)", p[0].String(), len(p) - 1); +} + + +// These constants control the construction of the ErrorList +// returned by GetErrors. +// +const ( + Raw = iota; // leave error list unchanged + Sorted; // sort error list by file, line, and column number + NoMultiples; // sort error list and leave only the first error per line +) + + +// GetErrorList returns the list of errors collected by an ErrorVector. +// The construction of the ErrorList returned is controlled by the mode +// parameter. If there are no errors, the result is nil. +// +func (h *ErrorVector) GetErrorList(mode int) ErrorList { + if h.errors.Len() == 0 { + return nil; + } + + list := make(ErrorList, h.errors.Len()); + for i := 0; i < h.errors.Len(); i++ { + list[i] = h.errors.At(i).(*Error); + } + + if mode >= Sorted { + sort.Sort(list); + } + + if mode >= NoMultiples { + var last token.Position; // initial last.Line is != any legal error line + i := 0; + for _, e := range list { + if e.Pos.Filename != last.Filename || e.Pos.Line != last.Line { + last = e.Pos; + list[i] = e; + i++; + } + } + list = list[0 : i]; + } + + return list; +} + + +// GetError is like GetErrorList, but it returns an os.Error instead +// so that a nil result can be assigned to an os.Error variable and +// remains nil. +// +func (h *ErrorVector) GetError(mode int) os.Error { + if h.errors.Len() == 0 { + return nil; + } + + return h.GetErrorList(mode); +} + + +// ErrorVector implements the ErrorHandler interface. +func (h *ErrorVector) Error(pos token.Position, msg string) { + h.errors.Push(&Error{pos, msg}); +} + + +// PrintError is a utility function that prints a list of errors to w, +// one error per line, if the err parameter is an ErrorList. Otherwise +// it prints the err string. +// +func PrintError(w io.Writer, err os.Error) { + if list, ok := err.(ErrorList); ok { + for _, e := range list { + fmt.Fprintf(w, "%s\n", e); + } + } else { + fmt.Fprintf(w, "%s\n", err); + } +} |