diff --git a/errors/errors.go b/errors/errors.go index 9451480..0eeeb61 100644 --- a/errors/errors.go +++ b/errors/errors.go @@ -87,29 +87,44 @@ func (pos Position) Union (other Position) Position { } // Error is an error that contains positional information. -type Error struct { - Position - Message string +type Error interface { + error + Position () Position } -var _ error = new(Error) -func (err *Error) Error () string { +type errInternal struct { + position Position + message string +} +var _ Error = new(errInternal) + +func (err *errInternal) Error () string { return err.String() } -func (err *Error) String () string { - return fmt.Sprintf("%v: %s", err.Position, err.Message) +func (err *errInternal) String () string { + return fmt.Sprintf("%v: %s", err.position, err.message) } -// Format produces a formatted printout of the error, and its location. -func (err *Error) Format () string { - return fmt.Sprintf("%v\n%v", err, err.Position.Format()) +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 &Error { - Position: position, - Message: fmt.Sprintf(format, variables...), +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. +func Format (err error) string { + if err, ok := err.(Error); ok { + return fmt.Sprintf("%v\n%v", err.Error(), err.Position().Format()) + } else { + return err.Error() } } diff --git a/errors/errors_test.go b/errors/errors_test.go index b602dfb..4418c34 100644 --- a/errors/errors_test.go +++ b/errors/errors_test.go @@ -8,16 +8,15 @@ testError (test, `example.fspl:11:7: some error 11 | lorem ipsum dolor ^^^^^`, -&Error { - Position: Position { +Errorf ( + Position { File: "example.fspl", Line: "lorem ipsum dolor", Row: 10, Start: 6, End: 11, }, - Message: "some error", -}) + "some error")) } func TestErrorTab (test *testing.T) { @@ -25,16 +24,15 @@ testError (test, `example.fspl:11:8: some error 11 | lorem ipsum dolor ^^^^^`, -&Error { - Position: Position { +Errorf ( + Position { File: "example.fspl", Line: "\tlorem\tipsum\tdolor", Row: 10, Start: 7, End: 12, }, - Message: "some error", -}) + "some error")) } func TestErrorTabInBetween (test *testing.T) { @@ -42,16 +40,15 @@ testError (test, `example.fspl:11:8: some error 11 | lorem ipsum dolor ^^^^^^^^^`, -&Error { - Position: Position { +Errorf ( + Position { File: "example.fspl", Line: "\tlorem\tipsum\tdolor", Row: 10, Start: 7, End: 14, }, - Message: "some error", -}) + "some error")) } func TestGetXInTabbedString (test *testing.T) { diff --git a/errors/test-common.go b/errors/test-common.go index f623884..cf19c04 100644 --- a/errors/test-common.go +++ b/errors/test-common.go @@ -11,6 +11,6 @@ func testString (test *testing.T, correct string, got string) { testcommon.Compare(test, correct, got) } -func testError (test *testing.T, correct string, err *Error) { - testString(test, correct, err.Format()) +func testError (test *testing.T, correct string, err Error) { + testString(test, correct, Format(err)) }