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

Commit 2d9c0a2

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 283b108 commit 2d9c0a2

File tree

5 files changed

+68
-27
lines changed

5 files changed

+68
-27
lines changed

vm/class.go

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

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

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

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

14181418
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: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,71 @@
11
package errors
22

3+
import "fmt"
4+
5+
type ErrorType int8
6+
37
const (
48
// InternalError is the default error type
5-
InternalError = "InternalError"
9+
InternalError ErrorType = iota
610
// IOError is an IO error such as file error
7-
IOError = "IOError"
11+
IOError
812
// ArgumentError is for an argument-related error
9-
ArgumentError = "ArgumentError"
13+
ArgumentError
1014
// NameError is for a constant-related error
11-
NameError = "NameError"
15+
NameError
1216
// StopIteration is raised when there are no more elements in an iterator
13-
StopIteration = "StopIteration"
17+
StopIteration
1418
// TypeError is for a type-related error
15-
TypeError = "TypeError"
19+
TypeError
1620
// NoMethodError is for an intentionally unsupported-method error
17-
NoMethodError = "NoMethodError"
21+
NoMethodError
1822
// ConstantAlreadyInitializedError means user re-declares twice
19-
ConstantAlreadyInitializedError = "ConstantAlreadyInitializedError"
23+
ConstantAlreadyInitializedError
2024
// HTTPError is returned when when a request fails to return a proper response
21-
HTTPError = "HTTPError"
25+
HTTPError
2226
// ZeroDivisionError is for zero-division by Integer/Float/Decimal value
23-
ZeroDivisionError = "ZeroDivisionError"
27+
ZeroDivisionError
2428
// ChannelCloseError is for accessing to the closed channel
25-
ChannelCloseError = "ChannelCloseError"
29+
ChannelCloseError
2630
// NotImplementedError means the method is missing
27-
NotImplementedError = "NotImplementedError"
31+
NotImplementedError
32+
33+
EndOfErrorTypeConst
2834
)
2935

36+
var errorTypesMap = map[ErrorType]string{
37+
InternalError: "InternalError",
38+
IOError: "IOError",
39+
ArgumentError: "ArgumentError",
40+
NameError: "NameError",
41+
StopIteration: "StopIteration",
42+
TypeError: "TypeError",
43+
NoMethodError: "NoMethodError",
44+
ConstantAlreadyInitializedError: "ConstantAlreadyInitializedError",
45+
HTTPError: "HTTPError",
46+
ZeroDivisionError: "ZeroDivisionError",
47+
ChannelCloseError: "ChannelCloseError",
48+
NotImplementedError: "NotImplementedError",
49+
}
50+
51+
func AllErrorTypes() []ErrorType {
52+
ts := make([]ErrorType, EndOfErrorTypeConst)
53+
for i := 0; i < int(EndOfErrorTypeConst); i++ {
54+
ts[i] = ErrorType(i)
55+
}
56+
return ts
57+
}
58+
59+
func GetErrorName(t ErrorType) string {
60+
v, ok := errorTypesMap[t]
61+
62+
if ok {
63+
return v
64+
}
65+
66+
panic(fmt.Errorf("expect to find ErrorType %d's name", t))
67+
}
68+
3069
/*
3170
Here defines different error message formats for different types of errors
3271
*/

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)