summaryrefslogtreecommitdiff
path: root/src/pkg/go/scanner/errors.go
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2009-07-14 10:44:57 -0700
committerRobert Griesemer <gri@golang.org>2009-07-14 10:44:57 -0700
commitb5318dcac20f5c1302975995b35f9883cf173cb0 (patch)
tree958b37c128124281cf2faae1191a55e15db02124 /src/pkg/go/scanner/errors.go
parentaf68bb2b309c186a519201f4c3bbcc339fdd064a (diff)
downloadgolang-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.go203
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);
+ }
+}