Skip to content
This repository was archived by the owner on Jul 12, 2025. It is now read-only.

Commit d2b2734

Browse files
committed
Refactor ErrorObject and Error classes' initialization
Currently, we allow raising errors from vm with any given string. This is a bad practice because any internal error should have a corresponding error class. This PR fixes this by only accepting pre-defined error types (enum) when initializing error objects. It also checks every error type (int) has a corresponding name (string) during vm initialization, which saves us the work to visually sync the 2 lists manually.
1 parent 44f3a14 commit d2b2734

File tree

5 files changed

+73
-27
lines changed

5 files changed

+73
-27
lines changed

vm/class.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,15 +1403,15 @@ var builtinClassCommonInstanceMethods = []*BuiltinMethodObject{
14031403
return t.vm.InitErrorObject(errors.InternalError, sourceLine, "%s", args[0].Inspect())
14041404
}
14051405

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

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

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

14171417
return t.vm.InitErrorObject(errors.ArgumentError, sourceLine, errors.WrongNumberOfArgumentLess, 2, aLen)

vm/error.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ type Error struct {
2222
message string
2323
stackTraces []string
2424
storedTraces bool
25-
Type string
2625
}
2726

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

3736
// InitErrorObject initializes and returns Error object
38-
func (vm *VM) InitErrorObject(errorType string, sourceLine int, format string, args ...interface{}) *Error {
39-
errClass := vm.objectClass.getClassConstant(errorType)
40-
37+
func (vm *VM) InitErrorObjectFromClass(errClass *RClass, sourceLine int, format string, args ...interface{}) *Error {
4138
t := &vm.mainThread
4239
cf := t.callFrameStack.top()
4340

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

62-
func (vm *VM) initErrorClasses() {
63-
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}
58+
// InitErrorObject initializes and returns Error object
59+
func (vm *VM) InitErrorObject(errorType errors.ErrorType, sourceLine int, format string, args ...interface{}) *Error {
60+
en := errors.GetErrorName(errorType)
61+
errClass := vm.objectClass.getClassConstant(en)
62+
return vm.InitErrorObjectFromClass(errClass, sourceLine, format, args...)
63+
}
6464

65-
for _, errType := range errTypes {
66-
c := vm.initializeClass(errType)
65+
func (vm *VM) initErrorClasses() {
66+
for _, et := range errors.AllErrorTypes() {
67+
en := errors.GetErrorName(et)
68+
c := vm.initializeClass(en)
6769
vm.objectClass.setClassConstant(c)
6870
}
6971
}

vm/errors/error.go

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,76 @@
11
package errors
22

3+
import "fmt"
4+
5+
// ErrorType is the enum representation for built-in error types
6+
type ErrorType int8
7+
38
const (
49
// InternalError is the default error type
5-
InternalError = "InternalError"
10+
InternalError ErrorType = iota
611
// IOError is an IO error such as file error
7-
IOError = "IOError"
12+
IOError
813
// ArgumentError is for an argument-related error
9-
ArgumentError = "ArgumentError"
14+
ArgumentError
1015
// NameError is for a constant-related error
11-
NameError = "NameError"
16+
NameError
1217
// StopIteration is raised when there are no more elements in an iterator
13-
StopIteration = "StopIteration"
18+
StopIteration
1419
// TypeError is for a type-related error
15-
TypeError = "TypeError"
20+
TypeError
1621
// NoMethodError is for an intentionally unsupported-method error
17-
NoMethodError = "NoMethodError"
22+
NoMethodError
1823
// ConstantAlreadyInitializedError means user re-declares twice
19-
ConstantAlreadyInitializedError = "ConstantAlreadyInitializedError"
24+
ConstantAlreadyInitializedError
2025
// HTTPError is returned when when a request fails to return a proper response
21-
HTTPError = "HTTPError"
26+
HTTPError
2227
// ZeroDivisionError is for zero-division by Integer/Float/Decimal value
23-
ZeroDivisionError = "ZeroDivisionError"
28+
ZeroDivisionError
2429
// ChannelCloseError is for accessing to the closed channel
25-
ChannelCloseError = "ChannelCloseError"
30+
ChannelCloseError
2631
// NotImplementedError means the method is missing
27-
NotImplementedError = "NotImplementedError"
32+
NotImplementedError
33+
34+
// EndOfErrorTypeConst is an anchor for getting all error types' enum values, see AllErrorTypes
35+
EndOfErrorTypeConst
2836
)
2937

38+
var errorTypesMap = map[ErrorType]string{
39+
InternalError: "InternalError",
40+
IOError: "IOError",
41+
ArgumentError: "ArgumentError",
42+
NameError: "NameError",
43+
StopIteration: "StopIteration",
44+
TypeError: "TypeError",
45+
NoMethodError: "NoMethodError",
46+
ConstantAlreadyInitializedError: "ConstantAlreadyInitializedError",
47+
HTTPError: "HTTPError",
48+
ZeroDivisionError: "ZeroDivisionError",
49+
ChannelCloseError: "ChannelCloseError",
50+
NotImplementedError: "NotImplementedError",
51+
}
52+
53+
54+
// AllErrorTypes returns all error types defined in this package in their enum format.
55+
func AllErrorTypes() []ErrorType {
56+
ts := make([]ErrorType, EndOfErrorTypeConst)
57+
for i := 0; i < int(EndOfErrorTypeConst); i++ {
58+
ts[i] = ErrorType(i)
59+
}
60+
return ts
61+
}
62+
63+
// GetErrorName receives an ErrorType enum and returns the corresponding error name.
64+
func GetErrorName(t ErrorType) string {
65+
v, ok := errorTypesMap[t]
66+
67+
if ok {
68+
return v
69+
}
70+
71+
panic(fmt.Errorf("expect to find ErrorType %d's name", t))
72+
}
73+
3074
/*
3175
Here defines different error message formats for different types of errors
3276
*/

vm/issue_vm.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func PrintError(v *VM) {
2828
if !ok {
2929
fmt.Println("No error detected")
3030
}
31-
fmt.Printf("# %s\n", err.Type)
31+
fmt.Printf("# %s\n", err.Class().Name)
3232
fmt.Println(err.Message())
3333

3434
fmt.Printf("### Goby version\n%s\n", Version)

vm/thread.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -490,14 +490,14 @@ func (t *Thread) reportArgumentError(sourceLine, idealArgNumber int, methodName
490490
}
491491

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

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

0 commit comments

Comments
 (0)