- 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
// 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
// environment, usually by pressing ctrl-c)

View file

@ -18,7 +18,7 @@ func (dsm *Disassembly) flowDisassembly(mc *cpu.CPU) error {
return err
}
switch err.(errors.AtariError).Errno {
switch err.(errors.AtariError).Head {
case errors.ProgramCounterCycled:
// originally, a cycled program counter caused the
// 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"
)
// Errno is used specified the specific error
type Errno int
// Values is the type used to specify arguments for FormattedErrors
type Values []interface{}
// 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.
type AtariError struct {
Errno Errno
Head string
Values Values
}
// 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{
Errno: errno,
Head: head,
Values: values,
}
}
@ -29,7 +26,7 @@ func New(errno Errno, values ...interface{}) AtariError {
// Error returns the normalised error message. Most usefully, it compresses
// duplicate adjacent AtariError instances.
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
p := strings.SplitN(s, ": ", 3)
@ -40,16 +37,17 @@ func (er AtariError) Error() string {
return strings.Join(p, ": ")
}
// Is checks if most recently wrapped error is an AtariError with a specific errno
func Is(err error, errno Errno) bool {
// Is checks if most recently wrapped error is an AtariError with a specific
// head
func Is(err error, head string) bool {
switch er := err.(type) {
case AtariError:
return er.Errno == errno
return er.Head == head
}
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 {
switch err.(type) {
case AtariError:
@ -58,16 +56,16 @@ func IsAny(err error) bool {
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
func Has(err error, errno Errno) bool {
if Is(err, errno) {
func Has(err error, head string) bool {
if Is(err, head) {
return true
}
for i := range err.(AtariError).Values {
if e, ok := err.(AtariError).Values[i].(error); ok {
if Has(e, errno) {
if Has(e, head) {
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
var messages = map[Errno]string{
// error messages
const (
// panics
PanicError: "panic: %v: %v",
PanicError = "panic: %v: %v"
// sentinals
UserInterrupt: "user interrupt",
UserSuspend: "user suspend",
ScriptEnd: "end of script (%v)",
PowerOff: "emulated machine has been powered off",
InputDeviceUnplugged: "controller unplugged from %v",
TVOutOfSpec: "tv out of spec: %v",
UserInterrupt = "user interrupt"
UserSuspend = "user suspend"
ScriptEnd = "end of script (%v)"
PowerOff = "emulated machine has been powered off"
InputDeviceUnplugged = "controller unplugged from %v"
TVOutOfSpec = "tv out of spec: %v"
// program modes
PlayError: "error emulating vcs: %v",
DebuggerError: "error debugging vcs: %v",
PerformanceError: "error during performance profiling: %v",
DisassemblyError: "error debugging disassembly: %v",
PlayError = "error emulating vcs: %v"
DebuggerError = "error debugging vcs: %v"
PerformanceError = "error during performance profiling: %v"
DisassemblyError = "error debugging disassembly: %v"
// debugger
ParserError: "parser error: %v: %v (char %d)", // first placeholder is the command definition
ValidationError: "%v for %v",
InvalidTarget: "invalid target (%v)",
CommandError: "%v",
TerminalError: "%v",
GUIEventError: "%v",
ReflectionNotRunning: "reflection process is not running",
ParserError = "parser error: %v: %v (char %d)" // first placeholder is the command definition
ValidationError = "%v for %v"
InvalidTarget = "invalid target (%v)"
CommandError = "%v"
TerminalError = "%v"
GUIEventError = "%v"
ReflectionNotRunning = "reflection process is not running"
// dissassembly
DisasmError: "disassembly error: %v",
DisasmError = "disassembly error: %v"
// script
ScriptFileError: "script error: %v",
ScriptFileUnavailable: "script error: cannot open script file (%v)",
ScriptRunError: "script error: use of '%v' is not allowed in scripts [%v::%d]",
ScriptScribeError: "script scribe error: %v",
ScriptFileError = "script error: %v"
ScriptFileUnavailable = "script error: cannot open script file (%v)"
ScriptRunError = "script error: use of '%v' is not allowed in scripts [%v::%d]"
ScriptScribeError = "script scribe error: %v"
// recorder
RecordingError: "controller recording error: %v",
PlaybackError: "controller playback error: %v",
PlaybackHashError: "controller playback error: hash error: %v",
RecordingError = "controller recording error: %v"
PlaybackError = "controller playback error: %v"
PlaybackHashError = "controller playback error: hash error: %v"
// database
DatabaseError: "database error: %v",
DatabaseReadError: "datbase error: %v [line %d]",
DatabaseSelectEmpty: "database error: no selected entries",
DatabaseKeyError: "database error: no such key in database [%v]",
DatabaseFileUnavailable: "database error: cannot open database (%v)",
DatabaseError = "database error: %v"
DatabaseReadError = "datbase error: %v [line %d]"
DatabaseSelectEmpty = "database error: no selected entries"
DatabaseKeyError = "database error: no such key in database [%v]"
DatabaseFileUnavailable = "database error: cannot open database (%v)"
// regression
RegressionError: "regression test error: %v",
RegressionDigestError: "digest entry: %v",
RegressionPlaybackError: "playback entry: %v",
RegressionError = "regression test error: %v"
RegressionDigestError = "digest entry: %v"
RegressionPlaybackError = "playback entry: %v"
// setup
SetupError: "setup error: %v",
SetupPanelError: "setup error: panel entry: %v",
SetupError = "setup error: %v"
SetupPanelError = "setup error: panel entry: %v"
// symbols
SymbolsFileError: "symbols error: error processing symbols file: %v",
SymbolsFileUnavailable: "symbols error: no symbols file for %v",
SymbolUnknown: "symbols error: unrecognised symbol (%v)",
SymbolsFileError = "symbols error: error processing symbols file: %v"
SymbolsFileUnavailable = "symbols error: no symbols file for %v"
SymbolUnknown = "symbols error: unrecognised symbol (%v)"
// cartridgeloader
CartridgeLoader: "cartridge loading error: %v",
CartridgeLoader = "cartridge loading error: %v"
// vcs
VCSError: "vcs error: %v",
PolycounterError: "polycounter error: %v",
VCSError = "vcs error: %v"
PolycounterError = "polycounter error: %v"
// cpu
UnimplementedInstruction: "cpu error: unimplemented instruction (%#02x) at (%#04x)",
InvalidResult: "cpu error: %v",
ProgramCounterCycled: "cpu error: program counter cycled back to 0x0000",
InvalidOperationMidInstruction: "cpu error: invalid operation mid-instruction (%v)",
UnimplementedInstruction = "cpu error: unimplemented instruction (%#02x) at (%#04x)"
InvalidResult = "cpu error: %v"
ProgramCounterCycled = "cpu error: program counter cycled back to 0x0000"
InvalidOperationMidInstruction = "cpu error: invalid operation mid-instruction (%v)"
// memory
MemoryError: "memory error: %v",
UnreadableAddress: "memory error: memory location is not readable (%#04x)",
UnwritableAddress: "memory error: memory location is not writable (%#04x)",
UnpokeableAddress: "memory error: cannot poke address (%v)",
UnpeekableAddress: "memory error: cannot peek address (%v)",
MemoryError = "memory error: %v"
UnreadableAddress = "memory error: memory location is not readable (%#04x)"
UnwritableAddress = "memory error: memory location is not writable (%#04x)"
UnpokeableAddress = "memory error: cannot poke address (%v)"
UnpeekableAddress = "memory error: cannot peek address (%v)"
// cartridges
CartridgeError: "cartridge error: %v",
CartridgeEjected: "cartridge error: no cartridge attached",
CartridgeError = "cartridge error: %v"
CartridgeEjected = "cartridge error: no cartridge attached"
// input
InputDeviceUnavailable: "input error: controller hardware unavailable (%v)",
UnknownInputEvent: "input error: %v: unsupported event (%v)",
InputDeviceUnavailable = "input error: controller hardware unavailable (%v)"
UnknownInputEvent = "input error: %v: unsupported event (%v)"
// television
UnknownTVRequest: "television error: unsupported request (%v)",
Television: "television error: %v",
UnknownTVRequest = "television error: unsupported request (%v)"
Television = "television error: %v"
// digests
VideoDigest: "video digest: %v",
AudioDigest: "audio digest: %v",
VideoDigest = "video digest: %v"
AudioDigest = "audio digest: %v"
// audio2wav
WavWriter: "wav writer: %v",
WavWriter = "wav writer: %v"
// gui
UnsupportedGUIRequest: "gui error: unsupported request (%v)",
SDL: "SDL: %v",
}
UnsupportedGUIRequest = "gui error: unsupported request (%v)"
SDL = "SDL: %v"
)

View file

@ -576,7 +576,7 @@ func testStrictAddressing(t *testing.T, mc *cpu.CPU, mem *mockMem) {
if err == nil {
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
} else {
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)
}
switch err.(errors.AtariError).Errno {
switch err.(errors.AtariError).Head {
// the PowerOff error is expected. if we receive it then that means
// the regression test has succeeded
case errors.PowerOff: