OSDN Git Service

libgo: Update to weekly.2011-11-02.
[pf3gnuchains/gcc-fork.git] / libgo / go / go / scanner / errors.go
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package scanner
6
7 import (
8         "fmt"
9         "go/token"
10         "io"
11         "sort"
12 )
13
14 // An implementation of an ErrorHandler may be provided to the Scanner.
15 // If a syntax error is encountered and a handler was installed, Error
16 // is called with a position and an error message. The position points
17 // to the beginning of the offending token.
18 //
19 type ErrorHandler interface {
20         Error(pos token.Position, msg string)
21 }
22
23 // ErrorVector implements the ErrorHandler interface. It maintains a list
24 // of errors which can be retrieved with GetErrorList and GetError. The
25 // zero value for an ErrorVector is an empty ErrorVector ready to use.
26 //
27 // A common usage pattern is to embed an ErrorVector alongside a
28 // scanner in a data structure that uses the scanner. By passing a
29 // reference to an ErrorVector to the scanner's Init call, default
30 // error handling is obtained.
31 //
32 type ErrorVector struct {
33         errors []*Error
34 }
35
36 // Reset resets an ErrorVector to no errors.
37 func (h *ErrorVector) Reset() { h.errors = h.errors[:0] }
38
39 // ErrorCount returns the number of errors collected.
40 func (h *ErrorVector) ErrorCount() int { return len(h.errors) }
41
42 // Within ErrorVector, an error is represented by an Error node. The
43 // position Pos, if valid, points to the beginning of the offending
44 // token, and the error condition is described by Msg.
45 //
46 type Error struct {
47         Pos token.Position
48         Msg string
49 }
50
51 func (e *Error) Error() string {
52         if e.Pos.Filename != "" || e.Pos.IsValid() {
53                 // don't print "<unknown position>"
54                 // TODO(gri) reconsider the semantics of Position.IsValid
55                 return e.Pos.String() + ": " + e.Msg
56         }
57         return e.Msg
58 }
59
60 // An ErrorList is a (possibly sorted) list of Errors.
61 type ErrorList []*Error
62
63 // ErrorList implements the sort Interface.
64 func (p ErrorList) Len() int      { return len(p) }
65 func (p ErrorList) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
66
67 func (p ErrorList) Less(i, j int) bool {
68         e := &p[i].Pos
69         f := &p[j].Pos
70         // Note that it is not sufficient to simply compare file offsets because
71         // the offsets do not reflect modified line information (through //line
72         // comments).
73         if e.Filename < f.Filename {
74                 return true
75         }
76         if e.Filename == f.Filename {
77                 if e.Line < f.Line {
78                         return true
79                 }
80                 if e.Line == f.Line {
81                         return e.Column < f.Column
82                 }
83         }
84         return false
85 }
86
87 func (p ErrorList) Error() string {
88         switch len(p) {
89         case 0:
90                 return "unspecified error"
91         case 1:
92                 return p[0].Error()
93         }
94         return fmt.Sprintf("%s (and %d more errors)", p[0], len(p)-1)
95 }
96
97 // These constants control the construction of the ErrorList
98 // returned by GetErrors.
99 //
100 const (
101         Raw         = iota // leave error list unchanged
102         Sorted             // sort error list by file, line, and column number
103         NoMultiples        // sort error list and leave only the first error per line
104 )
105
106 // GetErrorList returns the list of errors collected by an ErrorVector.
107 // The construction of the ErrorList returned is controlled by the mode
108 // parameter. If there are no errors, the result is nil.
109 //
110 func (h *ErrorVector) GetErrorList(mode int) ErrorList {
111         if len(h.errors) == 0 {
112                 return nil
113         }
114
115         list := make(ErrorList, len(h.errors))
116         copy(list, h.errors)
117
118         if mode >= Sorted {
119                 sort.Sort(list)
120         }
121
122         if mode >= NoMultiples {
123                 var last token.Position // initial last.Line is != any legal error line
124                 i := 0
125                 for _, e := range list {
126                         if e.Pos.Filename != last.Filename || e.Pos.Line != last.Line {
127                                 last = e.Pos
128                                 list[i] = e
129                                 i++
130                         }
131                 }
132                 list = list[0:i]
133         }
134
135         return list
136 }
137
138 // GetError is like GetErrorList, but it returns an error instead
139 // so that a nil result can be assigned to an error variable and
140 // remains nil.
141 //
142 func (h *ErrorVector) GetError(mode int) error {
143         if len(h.errors) == 0 {
144                 return nil
145         }
146
147         return h.GetErrorList(mode)
148 }
149
150 // ErrorVector implements the ErrorHandler interface.
151 func (h *ErrorVector) Error(pos token.Position, msg string) {
152         h.errors = append(h.errors, &Error{pos, msg})
153 }
154
155 // PrintError is a utility function that prints a list of errors to w,
156 // one error per line, if the err parameter is an ErrorList. Otherwise
157 // it prints the err string.
158 //
159 func PrintError(w io.Writer, err error) {
160         if list, ok := err.(ErrorList); ok {
161                 for _, e := range list {
162                         fmt.Fprintf(w, "%s\n", e)
163                 }
164         } else {
165                 fmt.Fprintf(w, "%s\n", err)
166         }
167 }