Skip to content

Commit f9b0894

Browse files
committed
Implement py.DeleteAttr, py.NewStringDictSized and DELETE_ATTR, BUILD_MAP, STORE_MAP opcodes
1 parent e387540 commit f9b0894

File tree

3 files changed

+60
-3
lines changed

3 files changed

+60
-3
lines changed

py/dict.go

+5
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ func NewStringDict() StringDict {
2424
return make(StringDict)
2525
}
2626

27+
// Make a new dictionary with reservation for n entries
28+
func NewStringDictSized(n int) StringDict {
29+
return make(StringDict, n)
30+
}
31+
2732
// Copy a dictionary
2833
func (d StringDict) Copy() StringDict {
2934
e := make(StringDict, len(d))

py/internal.go

+47
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,53 @@ func SetAttr(self Object, keyObj Object, value Object) Object {
240240
panic(ExceptionNewf(TypeError, "attribute name must be string, not '%s'", self.Type().Name))
241241
}
242242

243+
// DeleteAttrString
244+
func DeleteAttrString(self Object, key string) {
245+
// First look in type's dictionary etc for a property that could
246+
// be set - do this before looking in the instance dictionary
247+
deleter := self.Type().NativeGetAttrOrNil(key)
248+
if deleter != nil {
249+
// Call __set__ which writes properties etc
250+
if I, ok := deleter.(I__delete__); ok {
251+
I.M__delete__(self)
252+
return
253+
}
254+
}
255+
256+
// If we have __delattr__ then use that
257+
if I, ok := self.(I__delattr__); ok {
258+
I.M__delattr__(key)
259+
return
260+
} else if _, ok := TypeCall1(self, "__delattr__", String(key)); ok {
261+
return
262+
}
263+
264+
// Otherwise delete the attribute from the instance dictionary
265+
// if possible
266+
if I, ok := self.(IGetDict); ok {
267+
dict := I.GetDict()
268+
if dict == nil {
269+
panic(ExceptionNewf(SystemError, "nil Dict in %s", self.Type().Name))
270+
}
271+
if _, ok := dict[key]; ok {
272+
delete(dict, key)
273+
return
274+
}
275+
}
276+
277+
// If not blow up
278+
panic(ExceptionNewf(AttributeError, "'%s' object has no attribute '%s'", self.Type().Name, key))
279+
}
280+
281+
// DeleteAttr
282+
func DeleteAttr(self Object, keyObj Object) {
283+
if key, ok := keyObj.(String); ok {
284+
DeleteAttrString(self, string(key))
285+
return
286+
}
287+
panic(ExceptionNewf(TypeError, "attribute name must be string, not '%s'", self.Type().Name))
288+
}
289+
243290
// Call __next__ for the python object
244291
func Next(self Object) Object {
245292
if I, ok := self.(I__next__); ok {

vm/eval.go

+8-3
Original file line numberDiff line numberDiff line change
@@ -727,7 +727,7 @@ func do_STORE_ATTR(vm *Vm, namei int32) {
727727
// Implements del TOS.name, using namei as index into co_names.
728728
func do_DELETE_ATTR(vm *Vm, namei int32) {
729729
defer vm.CheckException()
730-
vm.NotImplemented("DELETE_ATTR", namei)
730+
py.DeleteAttrString(vm.POP(), vm.frame.Code.Names[namei])
731731
}
732732

733733
// Works as STORE_NAME, but stores the name as a global.
@@ -786,7 +786,7 @@ func do_BUILD_LIST(vm *Vm, count int32) {
786786
// pre-sized to hold count entries.
787787
func do_BUILD_MAP(vm *Vm, count int32) {
788788
defer vm.CheckException()
789-
vm.NotImplemented("BUILD_MAP", count)
789+
vm.PUSH(py.NewStringDictSized(int(count)))
790790
}
791791

792792
// Replaces TOS with getattr(TOS, co_names[namei]).
@@ -988,7 +988,12 @@ func do_SETUP_FINALLY(vm *Vm, delta int32) {
988988
// while leaving the dictionary on the stack.
989989
func do_STORE_MAP(vm *Vm, arg int32) {
990990
defer vm.CheckException()
991-
vm.NotImplemented("STORE_MAP", arg)
991+
key := string(vm.TOP().(py.String)) // FIXME
992+
value := vm.SECOND()
993+
dictObj := vm.THIRD()
994+
vm.DROPN(2)
995+
dict := dictObj.(py.StringDict)
996+
dict[key] = value
992997
}
993998

994999
// Pushes a reference to the local co_varnames[var_num] onto the stack.

0 commit comments

Comments
 (0)