Skip to content
This repository was archived by the owner on Jul 12, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions vm/class.go
Original file line number Diff line number Diff line change
Expand Up @@ -1403,15 +1403,15 @@ var builtinClassCommonInstanceMethods = []*BuiltinMethodObject{
return t.vm.InitErrorObject(errors.InternalError, sourceLine, "%s", args[0].Inspect())
}

return t.vm.InitErrorObject(errorClass.Name, sourceLine, "%s", args[0].Inspect())
return t.vm.InitErrorObjectFromClass(errorClass, sourceLine, "%s", args[0].Inspect())
case 2:
errorClass, ok := args[0].(*RClass)

if !ok {
return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongArgumentTypeFormatNum, 2, "a class", args[0].Class().Name)
}

return t.vm.InitErrorObject(errorClass.Name, sourceLine, "%s", args[1].Inspect())
return t.vm.InitErrorObjectFromClass(errorClass, sourceLine, "%s", args[1].Inspect())
}

return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgumentLess, 2, aLen)
Expand Down
22 changes: 12 additions & 10 deletions vm/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ type Error struct {
message string
stackTraces []string
storedTraces bool
Type string
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Type attribute is essentially the error's class name. So we don't need to store it separately.

}

// Internal functions ===================================================
Expand All @@ -35,9 +34,7 @@ func (vm *VM) InitNoMethodError(sourceLine int, methodName string, receiver Obje
}

// InitErrorObject initializes and returns Error object
func (vm *VM) InitErrorObject(errorType string, sourceLine int, format string, args ...interface{}) *Error {
errClass := vm.objectClass.getClassConstant(errorType)

func (vm *VM) InitErrorObjectFromClass(errClass *RClass, sourceLine int, format string, args ...interface{}) *Error {
t := &vm.mainThread
cf := t.callFrameStack.top()

Expand All @@ -53,17 +50,22 @@ func (vm *VM) InitErrorObject(errorType string, sourceLine int, format string, a
return &Error{
BaseObj: NewBaseObject(errClass),
// Add 1 to source line because it's zero indexed
message: fmt.Sprintf(errorType+": "+format, args...),
message: fmt.Sprintf(errClass.Name+": "+format, args...),
stackTraces: []string{fmt.Sprintf("from %s:%d", cf.FileName(), sourceLine)},
Type: errorType,
}
}

func (vm *VM) initErrorClasses() {
errTypes := []string{errors.InternalError, errors.IOError, errors.ArgumentError, errors.NameError, errors.StopIteration, errors.TypeError, errors.NoMethodError, errors.ConstantAlreadyInitializedError, errors.HTTPError, errors.ZeroDivisionError, errors.ChannelCloseError, errors.NotImplementedError}
// InitErrorObject initializes and returns Error object
func (vm *VM) InitErrorObject(errorType errors.ErrorType, sourceLine int, format string, args ...interface{}) *Error {
en := errors.GetErrorName(errorType)
errClass := vm.objectClass.getClassConstant(en)
return vm.InitErrorObjectFromClass(errClass, sourceLine, format, args...)
}

for _, errType := range errTypes {
c := vm.initializeClass(errType)
func (vm *VM) initErrorClasses() {
for _, et := range errors.AllErrorTypes() {
en := errors.GetErrorName(et)
c := vm.initializeClass(en)
vm.objectClass.setClassConstant(c)
}
}
Expand Down
68 changes: 56 additions & 12 deletions vm/errors/error.go
Original file line number Diff line number Diff line change
@@ -1,32 +1,76 @@
package errors

import "fmt"

// ErrorType is the enum representation for built-in error types
type ErrorType int8

const (
// InternalError is the default error type
InternalError = "InternalError"
InternalError ErrorType = iota
// IOError is an IO error such as file error
IOError = "IOError"
IOError
// ArgumentError is for an argument-related error
ArgumentError = "ArgumentError"
ArgumentError
// NameError is for a constant-related error
NameError = "NameError"
NameError
// StopIteration is raised when there are no more elements in an iterator
StopIteration = "StopIteration"
StopIteration
// TypeError is for a type-related error
TypeError = "TypeError"
TypeError
// NoMethodError is for an intentionally unsupported-method error
NoMethodError = "NoMethodError"
NoMethodError
// ConstantAlreadyInitializedError means user re-declares twice
ConstantAlreadyInitializedError = "ConstantAlreadyInitializedError"
ConstantAlreadyInitializedError
// HTTPError is returned when when a request fails to return a proper response
HTTPError = "HTTPError"
HTTPError
// ZeroDivisionError is for zero-division by Integer/Float/Decimal value
ZeroDivisionError = "ZeroDivisionError"
ZeroDivisionError
// ChannelCloseError is for accessing to the closed channel
ChannelCloseError = "ChannelCloseError"
ChannelCloseError
// NotImplementedError means the method is missing
NotImplementedError = "NotImplementedError"
NotImplementedError

// EndOfErrorTypeConst is an anchor for getting all error types' enum values, see AllErrorTypes
EndOfErrorTypeConst
)

var errorTypesMap = map[ErrorType]string{
InternalError: "InternalError",
IOError: "IOError",
ArgumentError: "ArgumentError",
NameError: "NameError",
StopIteration: "StopIteration",
TypeError: "TypeError",
NoMethodError: "NoMethodError",
ConstantAlreadyInitializedError: "ConstantAlreadyInitializedError",
HTTPError: "HTTPError",
ZeroDivisionError: "ZeroDivisionError",
ChannelCloseError: "ChannelCloseError",
NotImplementedError: "NotImplementedError",
}


// AllErrorTypes returns all error types defined in this package in their enum format.
func AllErrorTypes() []ErrorType {
ts := make([]ErrorType, EndOfErrorTypeConst)
for i := 0; i < int(EndOfErrorTypeConst); i++ {
ts[i] = ErrorType(i)
}
return ts
}

// GetErrorName receives an ErrorType enum and returns the corresponding error name.
func GetErrorName(t ErrorType) string {
v, ok := errorTypesMap[t]

if ok {
return v
}

panic(fmt.Errorf("expect to find ErrorType %d's name", t))
}

/*
Here defines different error message formats for different types of errors
*/
Expand Down
2 changes: 1 addition & 1 deletion vm/issue_vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func PrintError(v *VM) {
if !ok {
fmt.Println("No error detected")
}
fmt.Printf("# %s\n", err.Type)
fmt.Printf("# %s\n", err.Class().Name)
fmt.Println(err.Message())

fmt.Printf("### Goby version\n%s\n", Version)
Expand Down
4 changes: 2 additions & 2 deletions vm/thread.go
Original file line number Diff line number Diff line change
Expand Up @@ -490,14 +490,14 @@ func (t *Thread) reportArgumentError(sourceLine, idealArgNumber int, methodName
}

// pushErrorObject pushes the Error object to the stack
func (t *Thread) pushErrorObject(errorType string, sourceLine int, format string, args ...interface{}) {
func (t *Thread) pushErrorObject(errorType errors.ErrorType, sourceLine int, format string, args ...interface{}) {
err := t.vm.InitErrorObject(errorType, sourceLine, format, args...)
t.Stack.Push(&Pointer{Target: err})
panic(err.Message())
}

// setErrorObject replaces a certain stack element with the Error object
func (t *Thread) setErrorObject(receiverPtr, sp int, errorType string, sourceLine int, format string, args ...interface{}) {
func (t *Thread) setErrorObject(receiverPtr, sp int, errorType errors.ErrorType, sourceLine int, format string, args ...interface{}) {
err := t.vm.InitErrorObject(errorType, sourceLine, format, args...)
t.Stack.Set(receiverPtr, &Pointer{Target: err})
t.Stack.pointer = sp
Expand Down