Skip to content

Commit 5aeba6f

Browse files
committed
Work on exceptions
* Improve internal interfaces for making and using exceptions * Catch and check exceptions in the vm * raise exceptions in the vm * Unwind blocks (more work to do) in the vm
1 parent 6980c03 commit 5aeba6f

File tree

5 files changed

+446
-117
lines changed

5 files changed

+446
-117
lines changed

py/exception.go

Lines changed: 117 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ var (
6262
SyntaxError = ExceptionType.NewType("SyntaxError", "Invalid syntax.", nil, nil)
6363
IndentationError = SyntaxError.NewType("IndentationError", "Improper indentation.", nil, nil)
6464
TabError = IndentationError.NewType("TabError", "Improper mixture of spaces and tabs.", nil, nil)
65-
SystemError = ExceptionType.NewType("SystemError", "Internal error in the Python interpreter.\n\nPlease report this to the Python maintainer, along with the traceback,\nthe Python version, and the hardware/OS platform and version.", nil, nil)
65+
SystemError = ExceptionType.NewType("SystemError", "Internal error in the Gpython interpreter.\n\nPlease report this to the Gpython maintainer, along with the traceback,\nthe Gpython version, and the hardware/OS platform and version.", nil, nil)
6666
TypeError = ExceptionType.NewType("TypeError", "Inappropriate argument type.", nil, nil)
6767
ValueError = ExceptionType.NewType("ValueError", "Inappropriate argument value (of correct type).", nil, nil)
6868
UnicodeError = ValueError.NewType("UnicodeError", "Unicode related error.", nil, nil)
@@ -81,15 +81,20 @@ var (
8181
BytesWarning = Warning.NewType("BytesWarning", "Base class for warnings about bytes and buffer related problems, mostly\nrelated to conversion from str or comparing to str.", nil, nil)
8282
ResourceWarning = Warning.NewType("ResourceWarning", "Base class for warnings about resource usage.", nil, nil)
8383
// Singleton exceptions
84-
NotImplemented = NotImplementedError.M__call__(nil, nil)
84+
NotImplemented = ExceptionNew(NotImplementedError, nil, nil)
8585
)
8686

8787
// Type of this object
88-
func (o *Exception) Type() *Type {
89-
return o.Base
88+
func (e *Exception) Type() *Type {
89+
return e.Base
9090
}
9191

92-
// RangeNew
92+
// Go error interface
93+
func (e *Exception) Error() string {
94+
return fmt.Sprintf("%s: %v", e.Base.Name, e.Args)
95+
}
96+
97+
// ExceptionNew
9398
func ExceptionNew(metatype *Type, args Tuple, kwargs StringDict) Object {
9499
if len(kwargs) != 0 {
95100
// TypeError
@@ -101,6 +106,56 @@ func ExceptionNew(metatype *Type, args Tuple, kwargs StringDict) Object {
101106
}
102107
}
103108

109+
// ExceptionNewf - make a new exception with fmt parameters
110+
func ExceptionNewf(metatype *Type, format string, a ...interface{}) *Exception {
111+
message := fmt.Sprintf(format, a...)
112+
return &Exception{
113+
Base: metatype,
114+
Args: Tuple{String(message)},
115+
}
116+
}
117+
118+
/*
119+
if py.ExceptionClassCheck(exc) {
120+
t = exc.(*py.Type)
121+
value = py.Call(exc, nil, nil)
122+
if value == nil {
123+
return exitException
124+
}
125+
if !py.ExceptionInstanceCheck(value) {
126+
PyErr_Format(PyExc_TypeError, "calling %s should have returned an instance of BaseException, not %s", t.Name, value.Type().Name)
127+
return exitException
128+
}
129+
} else if t = py.ExceptionInstanceCheck(exc); t != nil {
130+
value = exc
131+
} else {
132+
// Not something you can raise. You get an exception
133+
// anyway, just not what you specified :-)
134+
PyErr_SetString(PyExc_TypeError, "exceptions must derive from BaseException")
135+
return exitException
136+
}
137+
*/
138+
139+
// Coerce an object into an exception one way or another
140+
func MakeException(r interface{}) *Exception {
141+
switch x := r.(type) {
142+
case *Exception:
143+
return x
144+
case *Type:
145+
if x.Flags&TPFLAGS_BASE_EXC_SUBCLASS != 0 {
146+
return ExceptionNew(x, nil, nil).(*Exception)
147+
} else {
148+
return ExceptionNewf(TypeError, "exceptions must derive from BaseException")
149+
}
150+
case error:
151+
return ExceptionNew(SystemError, Tuple{String(x.Error())}, nil).(*Exception)
152+
case string:
153+
return ExceptionNew(SystemError, Tuple{String(x)}, nil).(*Exception)
154+
default:
155+
return ExceptionNew(SystemError, Tuple{String(fmt.Sprintf("Unknown error %#v", r))}, nil).(*Exception)
156+
}
157+
}
158+
104159
/*
105160
#define PyType_HasFeature(t,f) (((t)->tp_flags & (f)) != 0)
106161
@@ -123,3 +178,60 @@ func ExceptionNew(metatype *Type, args Tuple, kwargs StringDict) Object {
123178
124179
#define PyExceptionInstance_Class(x) ((PyObject*)((x)->ob_type))
125180
*/
181+
182+
// Checks that the object passed in is a class and is an exception
183+
func ExceptionClassCheck(err Object) bool {
184+
if t, ok := err.(*Type); ok {
185+
return t.Flags&TPFLAGS_BASE_EXC_SUBCLASS != 0
186+
}
187+
return false
188+
}
189+
190+
// Check to see if err matches exc
191+
//
192+
// exc can be a tuple
193+
//
194+
// Used in except statements
195+
func ExceptionGivenMatches(err, exc Object) bool {
196+
if err == nil || exc == nil {
197+
// maybe caused by "import exceptions" that failed early on
198+
return false
199+
}
200+
201+
// Test the tuple case recursively
202+
if excTuple, ok := exc.(Tuple); ok {
203+
for i := 0; i < len(excTuple); i++ {
204+
if ExceptionGivenMatches(err, excTuple[i]) {
205+
return true
206+
}
207+
}
208+
return false
209+
}
210+
211+
// err might be an instance, so check its class.
212+
if exception, ok := err.(*Exception); ok {
213+
err = exception.Type()
214+
}
215+
216+
if ExceptionClassCheck(err) && ExceptionClassCheck(exc) {
217+
res := false
218+
// PyObject *exception, *value, *tb;
219+
// PyErr_Fetch(&exception, &value, &tb);
220+
221+
// PyObject_IsSubclass() can recurse and therefore is
222+
// not safe (see test_bad_getattr in test.pickletester).
223+
res = err.(*Type).IsSubtype(exc.(*Type))
224+
// This function must not fail, so print the error here
225+
// if (res == -1) {
226+
// PyErr_WriteUnraisable(err);
227+
// res = false
228+
// }
229+
// PyErr_Restore(exception, value, tb);
230+
return res
231+
}
232+
233+
return err == exc
234+
}
235+
236+
// Check Interfaces
237+
var _ error = (*Exception)(nil)

py/type.go

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -172,15 +172,23 @@ var TypeType *Type = &Type{
172172
Name: "type",
173173
Doc: "type(object) -> the object's type\ntype(name, bases, dict) -> a new type",
174174
}
175-
var ObjectType = TypeType.NewType("object", "The most base type", ObjectNew, ObjectInit)
175+
176+
var ObjectType = &Type{
177+
Name: "object",
178+
Doc: "The most base type",
179+
Flags: TPFLAGS_BASETYPE,
180+
}
176181

177182
func init() {
178183
// Initialises like this to avoid initialisation loops
179184
TypeType.New = TypeNew
180185
TypeType.Init = TypeInit
181186
TypeType.ObjectType = TypeType
182-
// FIXME put this into NewType
183-
ObjectType.Flags |= TPFLAGS_BASETYPE
187+
ObjectType.New = ObjectNew
188+
ObjectType.Init = ObjectInit
189+
ObjectType.ObjectType = TypeType
190+
TypeType.Ready()
191+
ObjectType.Ready()
184192
}
185193

186194
// Type of this object
@@ -192,24 +200,28 @@ func (t *Type) Type() *Type {
192200
//
193201
// For making Go types
194202
func NewType(Name string, Doc string) *Type {
195-
return &Type{
203+
t := &Type{
196204
ObjectType: TypeType,
197205
Name: Name,
198206
Doc: Doc,
199207
}
208+
//t.Ready()
209+
return t
200210
}
201211

202212
// Make a new type with constructors
203213
//
204214
// For making Go types
205215
func NewTypeX(Name string, Doc string, New NewFunc, Init InitFunc) *Type {
206-
return &Type{
216+
t := &Type{
207217
ObjectType: TypeType,
208218
Name: Name,
209219
Doc: Doc,
210220
New: New,
211221
Init: Init,
212222
}
223+
//t.Ready()
224+
return t
213225
}
214226

215227
// Make a subclass of a type
@@ -223,13 +235,17 @@ func (t *Type) NewType(Name string, Doc string, New NewFunc, Init InitFunc) *Typ
223235
if Init == nil {
224236
Init = t.Init
225237
}
226-
return &Type{
238+
// FIXME inherit more stuff
239+
tt := &Type{
227240
ObjectType: t,
228241
Name: Name,
229242
Doc: Doc,
230243
New: New,
231244
Init: Init,
245+
Flags: t.Flags, // FIXME not sure this is correct!
232246
}
247+
//tt.Ready()
248+
return tt
233249
}
234250

235251
// Determine the most derived metatype.
@@ -1474,14 +1490,16 @@ func ObjectInit(self Object, args Tuple, kwargs StringDict) {
14741490
}
14751491
// Call the __init__ method if it exists
14761492
// FIXME this isn't the way cpython does it - it adjusts the function pointers
1477-
t = self.(*Type)
1478-
init := t.GetAttrOrNil("__init__")
1479-
fmt.Printf("init = %v\n", init)
1480-
if init != nil {
1481-
newArgs := make(Tuple, len(args)+1)
1482-
newArgs[0] = self
1483-
copy(newArgs[1:], args)
1484-
Call(init, newArgs, kwargs)
1493+
// Only do this for non built in types
1494+
if t, ok := self.(*Type); ok {
1495+
init := t.GetAttrOrNil("__init__")
1496+
fmt.Printf("init = %v\n", init)
1497+
if init != nil {
1498+
newArgs := make(Tuple, len(args)+1)
1499+
newArgs[0] = self
1500+
copy(newArgs[1:], args)
1501+
Call(init, newArgs, kwargs)
1502+
}
14851503
}
14861504
}
14871505

0 commit comments

Comments
 (0)