The Go Programming Language

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

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.