63 lines
1.6 KiB
Go
63 lines
1.6 KiB
Go
package parse
|
|
|
|
import "fmt"
|
|
|
|
// Error is an error that contains positional information.
|
|
type Error interface {
|
|
error
|
|
Position () Position
|
|
}
|
|
|
|
type errInternal struct {
|
|
position Position
|
|
message string
|
|
}
|
|
var _ Error = new(errInternal)
|
|
|
|
func (err *errInternal) Error () string {
|
|
return err.String()
|
|
}
|
|
|
|
func (err *errInternal) String () string {
|
|
return err.message
|
|
}
|
|
|
|
func (err *errInternal) Position () Position {
|
|
return err.position
|
|
}
|
|
|
|
// Errorf produces an error with a fmt'd message.
|
|
func Errorf (position Position, format string, variables ...any) Error {
|
|
return &errInternal {
|
|
position: position,
|
|
message: fmt.Sprintf(format, variables...),
|
|
}
|
|
}
|
|
|
|
// Format returns a formatted string representing an error. This string may take
|
|
// up multiple lines and contain ANSI escape codes. If err does not fulfill the
|
|
// Error interface, err.Error() is returned instead.
|
|
//
|
|
// When the error fulfills the Error interface, the formatted output will
|
|
// be of the general form:
|
|
// FILE:ROW+1:START+1: MESSAGE
|
|
// ROW+1 | LINE
|
|
// ^^^^
|
|
// Where the position of the underline (^^^^) corresponds to the start and end
|
|
// fields in the error's position. Note that the row and column numbers as
|
|
// displayed are increased by one from their normal zero-indexed state, because
|
|
// most editors display row and column numbers starting at 1:1. Additionally,
|
|
// because normal error messages do not produce trailing line breaks, neither
|
|
// does this function.
|
|
func Format (err error) string {
|
|
if e, ok := err.(Error); ok {
|
|
return fmt.Sprintf (
|
|
"%v: %v\n%v",
|
|
e.Position(),
|
|
e.Error(),
|
|
e.Position().Format())
|
|
} else {
|
|
return err.Error()
|
|
}
|
|
}
|