- removed ErrorID, using the error message as the ID
    - works just as well and simplifies maintenance
    - the messages should be moved to the relevant packages OR to a
      locale package. not sure which yet.
This commit is contained in:
steve 2019-12-21 20:32:09 +00:00
parent bdb4fe6a83
commit d7cdfcfe61
10 changed files with 104 additions and 203 deletions

View file

@ -164,7 +164,7 @@ func (dbg *Debugger) inputLoop(inputter terminal.Input, videoCycle bool) error {
// we now know the we have an Atari Error so we can safely // we now know the we have an Atari Error so we can safely
// switch on the internal Errno // switch on the internal Errno
switch err.(errors.AtariError).Errno { switch err.(errors.AtariError).Head {
// user interrupts are triggered by the user (in a terminal // user interrupts are triggered by the user (in a terminal
// environment, usually by pressing ctrl-c) // environment, usually by pressing ctrl-c)

View file

@ -18,7 +18,7 @@ func (dsm *Disassembly) flowDisassembly(mc *cpu.CPU) error {
return err return err
} }
switch err.(errors.AtariError).Errno { switch err.(errors.AtariError).Head {
case errors.ProgramCounterCycled: case errors.ProgramCounterCycled:
// originally, a cycled program counter caused the // originally, a cycled program counter caused the
// disassembly to end but thinking about it a bit more, // disassembly to end but thinking about it a bit more,

View file

@ -1,120 +0,0 @@
package errors
// list of error numbers
const (
// PanicErrors should be used only as an alternative to panic(). that is
// errors where there is no good response beyond suggesting that a terrible
// mistake has been made. PanicErrors should be treated like actual
// panic()s and cause the program (or the sub-system) to cease as soon as
// possible.
//
// if is not practical to cause the program to cease then at the very
// least, the PanicError should result in the display of the error message
// in big, friendly letters.
//
// actual panic()s should only be used when the mistake is so heinous that
// it suggests a fundamental misunderstanding has taken place and so, as it
// were, all bets are off.
PanicError Errno = iota
// sentinal
UserInterrupt
UserSuspend
ScriptEnd
PowerOff
InputDeviceUnplugged
TVOutOfSpec
// program modes
PlayError
DebuggerError
PerformanceError
DisassemblyError
// debugger
ParserError
ValidationError
InvalidTarget
CommandError
TerminalError
GUIEventError
ReflectionNotRunning
// disassembly
DisasmError
// script
ScriptScribeError
ScriptFileUnavailable
ScriptFileError
ScriptRunError
// recorder
RecordingError
PlaybackError
PlaybackHashError
// database
DatabaseError
DatabaseReadError
DatabaseSelectEmpty
DatabaseKeyError
DatabaseFileUnavailable
// regression
RegressionError
RegressionDigestError
RegressionPlaybackError
// setup
SetupError
SetupPanelError
// symbols
SymbolsFileUnavailable
SymbolsFileError
SymbolUnknown
// cartridgeloader
CartridgeLoader
// vcs
VCSError
PolycounterError
// cpu
UnimplementedInstruction
InvalidResult
ProgramCounterCycled
InvalidOperationMidInstruction
// memory
MemoryError
UnreadableAddress
UnwritableAddress
UnpokeableAddress
UnpeekableAddress
// cartridges
CartridgeError
CartridgeEjected
// input
InputDeviceUnavailable
UnknownInputEvent
// tv
UnknownTVRequest
Television
// digests
VideoDigest
AudioDigest
// wavwriter
WavWriter
// gui
UnsupportedGUIRequest
SDL
)

View file

@ -5,23 +5,20 @@ import (
"strings" "strings"
) )
// Errno is used specified the specific error
type Errno int
// Values is the type used to specify arguments for FormattedErrors // Values is the type used to specify arguments for FormattedErrors
type Values []interface{} type Values []interface{}
// AtariError allows code to specify a predefined error and not worry too much about the // AtariError allows code to specify a predefined error and not worry too much about the
// message behind that error and how the message will be formatted on output. // message behind that error and how the message will be formatted on output.
type AtariError struct { type AtariError struct {
Errno Errno Head string
Values Values Values Values
} }
// New is used to create a new instance of an AtariError. // New is used to create a new instance of an AtariError.
func New(errno Errno, values ...interface{}) AtariError { func New(head string, values ...interface{}) AtariError {
return AtariError{ return AtariError{
Errno: errno, Head: head,
Values: values, Values: values,
} }
} }
@ -29,7 +26,7 @@ func New(errno Errno, values ...interface{}) AtariError {
// Error returns the normalised error message. Most usefully, it compresses // Error returns the normalised error message. Most usefully, it compresses
// duplicate adjacent AtariError instances. // duplicate adjacent AtariError instances.
func (er AtariError) Error() string { func (er AtariError) Error() string {
s := fmt.Sprintf(messages[er.Errno], er.Values...) s := fmt.Sprintf(er.Head, er.Values...)
// de-duplicate error message parts // de-duplicate error message parts
p := strings.SplitN(s, ": ", 3) p := strings.SplitN(s, ": ", 3)
@ -40,16 +37,17 @@ func (er AtariError) Error() string {
return strings.Join(p, ": ") return strings.Join(p, ": ")
} }
// Is checks if most recently wrapped error is an AtariError with a specific errno // Is checks if most recently wrapped error is an AtariError with a specific
func Is(err error, errno Errno) bool { // head
func Is(err error, head string) bool {
switch er := err.(type) { switch er := err.(type) {
case AtariError: case AtariError:
return er.Errno == errno return er.Head == head
} }
return false return false
} }
// IsAny checks if most recently wrapped error is an AtariError, with any errno // IsAny checks if most recently wrapped error is an AtariError, with any head
func IsAny(err error) bool { func IsAny(err error) bool {
switch err.(type) { switch err.(type) {
case AtariError: case AtariError:
@ -58,16 +56,16 @@ func IsAny(err error) bool {
return false return false
} }
// Has checks to see if the specified AtariError errno appears somewhere in the // Has checks to see if the specified AtariError head appears somewhere in the
// sequence of wrapped errors // sequence of wrapped errors
func Has(err error, errno Errno) bool { func Has(err error, head string) bool {
if Is(err, errno) { if Is(err, head) {
return true return true
} }
for i := range err.(AtariError).Values { for i := range err.(AtariError).Values {
if e, ok := err.(AtariError).Values[i].(error); ok { if e, ok := err.(AtariError).Values[i].(error); ok {
if Has(e, errno) { if Has(e, head) {
return true return true
} }
} }

22
errors/errors_test.go Normal file
View file

@ -0,0 +1,22 @@
package errors_test
import (
"fmt"
"gopher2600/errors"
"testing"
)
func TestError(t *testing.T) {
e := errors.New(errors.SetupError, "foo")
if e.Error() != "setup error: foo" {
t.Errorf("unexpected error message")
}
// packing errors of the same type next to each other causes
// one of them to be dropped
f := errors.New(errors.SetupError, e)
fmt.Println(f.Error())
if f.Error() != "setup error: foo" {
t.Errorf("unexpected duplicate error message")
}
}

View file

@ -1,107 +1,108 @@
package errors package errors
var messages = map[Errno]string{ // error messages
const (
// panics // panics
PanicError: "panic: %v: %v", PanicError = "panic: %v: %v"
// sentinals // sentinals
UserInterrupt: "user interrupt", UserInterrupt = "user interrupt"
UserSuspend: "user suspend", UserSuspend = "user suspend"
ScriptEnd: "end of script (%v)", ScriptEnd = "end of script (%v)"
PowerOff: "emulated machine has been powered off", PowerOff = "emulated machine has been powered off"
InputDeviceUnplugged: "controller unplugged from %v", InputDeviceUnplugged = "controller unplugged from %v"
TVOutOfSpec: "tv out of spec: %v", TVOutOfSpec = "tv out of spec: %v"
// program modes // program modes
PlayError: "error emulating vcs: %v", PlayError = "error emulating vcs: %v"
DebuggerError: "error debugging vcs: %v", DebuggerError = "error debugging vcs: %v"
PerformanceError: "error during performance profiling: %v", PerformanceError = "error during performance profiling: %v"
DisassemblyError: "error debugging disassembly: %v", DisassemblyError = "error debugging disassembly: %v"
// debugger // debugger
ParserError: "parser error: %v: %v (char %d)", // first placeholder is the command definition ParserError = "parser error: %v: %v (char %d)" // first placeholder is the command definition
ValidationError: "%v for %v", ValidationError = "%v for %v"
InvalidTarget: "invalid target (%v)", InvalidTarget = "invalid target (%v)"
CommandError: "%v", CommandError = "%v"
TerminalError: "%v", TerminalError = "%v"
GUIEventError: "%v", GUIEventError = "%v"
ReflectionNotRunning: "reflection process is not running", ReflectionNotRunning = "reflection process is not running"
// dissassembly // dissassembly
DisasmError: "disassembly error: %v", DisasmError = "disassembly error: %v"
// script // script
ScriptFileError: "script error: %v", ScriptFileError = "script error: %v"
ScriptFileUnavailable: "script error: cannot open script file (%v)", ScriptFileUnavailable = "script error: cannot open script file (%v)"
ScriptRunError: "script error: use of '%v' is not allowed in scripts [%v::%d]", ScriptRunError = "script error: use of '%v' is not allowed in scripts [%v::%d]"
ScriptScribeError: "script scribe error: %v", ScriptScribeError = "script scribe error: %v"
// recorder // recorder
RecordingError: "controller recording error: %v", RecordingError = "controller recording error: %v"
PlaybackError: "controller playback error: %v", PlaybackError = "controller playback error: %v"
PlaybackHashError: "controller playback error: hash error: %v", PlaybackHashError = "controller playback error: hash error: %v"
// database // database
DatabaseError: "database error: %v", DatabaseError = "database error: %v"
DatabaseReadError: "datbase error: %v [line %d]", DatabaseReadError = "datbase error: %v [line %d]"
DatabaseSelectEmpty: "database error: no selected entries", DatabaseSelectEmpty = "database error: no selected entries"
DatabaseKeyError: "database error: no such key in database [%v]", DatabaseKeyError = "database error: no such key in database [%v]"
DatabaseFileUnavailable: "database error: cannot open database (%v)", DatabaseFileUnavailable = "database error: cannot open database (%v)"
// regression // regression
RegressionError: "regression test error: %v", RegressionError = "regression test error: %v"
RegressionDigestError: "digest entry: %v", RegressionDigestError = "digest entry: %v"
RegressionPlaybackError: "playback entry: %v", RegressionPlaybackError = "playback entry: %v"
// setup // setup
SetupError: "setup error: %v", SetupError = "setup error: %v"
SetupPanelError: "setup error: panel entry: %v", SetupPanelError = "setup error: panel entry: %v"
// symbols // symbols
SymbolsFileError: "symbols error: error processing symbols file: %v", SymbolsFileError = "symbols error: error processing symbols file: %v"
SymbolsFileUnavailable: "symbols error: no symbols file for %v", SymbolsFileUnavailable = "symbols error: no symbols file for %v"
SymbolUnknown: "symbols error: unrecognised symbol (%v)", SymbolUnknown = "symbols error: unrecognised symbol (%v)"
// cartridgeloader // cartridgeloader
CartridgeLoader: "cartridge loading error: %v", CartridgeLoader = "cartridge loading error: %v"
// vcs // vcs
VCSError: "vcs error: %v", VCSError = "vcs error: %v"
PolycounterError: "polycounter error: %v", PolycounterError = "polycounter error: %v"
// cpu // cpu
UnimplementedInstruction: "cpu error: unimplemented instruction (%#02x) at (%#04x)", UnimplementedInstruction = "cpu error: unimplemented instruction (%#02x) at (%#04x)"
InvalidResult: "cpu error: %v", InvalidResult = "cpu error: %v"
ProgramCounterCycled: "cpu error: program counter cycled back to 0x0000", ProgramCounterCycled = "cpu error: program counter cycled back to 0x0000"
InvalidOperationMidInstruction: "cpu error: invalid operation mid-instruction (%v)", InvalidOperationMidInstruction = "cpu error: invalid operation mid-instruction (%v)"
// memory // memory
MemoryError: "memory error: %v", MemoryError = "memory error: %v"
UnreadableAddress: "memory error: memory location is not readable (%#04x)", UnreadableAddress = "memory error: memory location is not readable (%#04x)"
UnwritableAddress: "memory error: memory location is not writable (%#04x)", UnwritableAddress = "memory error: memory location is not writable (%#04x)"
UnpokeableAddress: "memory error: cannot poke address (%v)", UnpokeableAddress = "memory error: cannot poke address (%v)"
UnpeekableAddress: "memory error: cannot peek address (%v)", UnpeekableAddress = "memory error: cannot peek address (%v)"
// cartridges // cartridges
CartridgeError: "cartridge error: %v", CartridgeError = "cartridge error: %v"
CartridgeEjected: "cartridge error: no cartridge attached", CartridgeEjected = "cartridge error: no cartridge attached"
// input // input
InputDeviceUnavailable: "input error: controller hardware unavailable (%v)", InputDeviceUnavailable = "input error: controller hardware unavailable (%v)"
UnknownInputEvent: "input error: %v: unsupported event (%v)", UnknownInputEvent = "input error: %v: unsupported event (%v)"
// television // television
UnknownTVRequest: "television error: unsupported request (%v)", UnknownTVRequest = "television error: unsupported request (%v)"
Television: "television error: %v", Television = "television error: %v"
// digests // digests
VideoDigest: "video digest: %v", VideoDigest = "video digest: %v"
AudioDigest: "audio digest: %v", AudioDigest = "audio digest: %v"
// audio2wav // audio2wav
WavWriter: "wav writer: %v", WavWriter = "wav writer: %v"
// gui // gui
UnsupportedGUIRequest: "gui error: unsupported request (%v)", UnsupportedGUIRequest = "gui error: unsupported request (%v)"
SDL: "SDL: %v", SDL = "SDL: %v"
} )

View file

@ -576,7 +576,7 @@ func testStrictAddressing(t *testing.T, mc *cpu.CPU, mem *mockMem) {
if err == nil { if err == nil {
t.Fatalf("not recieved an UnreadableAddress error when we should") t.Fatalf("not recieved an UnreadableAddress error when we should")
} }
if err.(errors.AtariError).Errno == errors.UnreadableAddress { if err.(errors.AtariError).Head == errors.UnreadableAddress {
// this is okay // this is okay
} else { } else {
t.Fatalf("error during CPU step (%v)\n", err) t.Fatalf("error during CPU step (%v)\n", err)

0
patch/doc.go Normal file
View file

0
patch/patch.go Normal file
View file

View file

@ -148,7 +148,7 @@ func (reg *PlaybackRegression) regress(newRegression bool, output io.Writer, msg
return false, "", errors.New(errors.RegressionPlaybackError, err) return false, "", errors.New(errors.RegressionPlaybackError, err)
} }
switch err.(errors.AtariError).Errno { switch err.(errors.AtariError).Head {
// the PowerOff error is expected. if we receive it then that means // the PowerOff error is expected. if we receive it then that means
// the regression test has succeeded // the regression test has succeeded
case errors.PowerOff: case errors.PowerOff: