Skip to content

Commit 9510b77

Browse files
committed
Implement LOAD_ATTR/py.GetAttr
1 parent 058a4e2 commit 9510b77

File tree

3 files changed

+58
-3
lines changed

3 files changed

+58
-3
lines changed

py/internal.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,53 @@ func SetItem(self Object, key Object, value Object) Object {
9898
// FIXME should be TypeError
9999
panic(fmt.Sprintf("TypeError: '%s' object does not support item assignment", self.Type().Name))
100100
}
101+
102+
// GetAttrOrNil - returns the result nil if attribute not found
103+
func GetAttrOrNil(self Object, key string) Object {
104+
// Call __getattribute unconditionally if it exists
105+
if I, ok := self.(I__getattribute__); ok {
106+
return I.M__getattribute__(Object(String(key)))
107+
} else if res, ok := TypeCall1(self, "__getattribute__", Object(String(key))); ok {
108+
// FIXME catch AttributeError here
109+
return res
110+
}
111+
112+
if t, ok := self.(*Type); ok {
113+
// Now look in the instance dictionary etc
114+
res := t.GetAttrOrNil(key)
115+
if res != nil {
116+
return res
117+
}
118+
} else {
119+
// FIXME introspection for M__methods__ on non *Type objects
120+
}
121+
122+
// And now only if not found call __getattr__
123+
if I, ok := self.(I__getattr__); ok {
124+
return I.M__getattr__(Object(String(key)))
125+
} else if res, ok := TypeCall1(self, "__getitem__", Object(String(key))); ok {
126+
return res
127+
}
128+
129+
// Not found - return nil
130+
return nil
131+
}
132+
133+
// GetAttrString
134+
func GetAttrString(self Object, key string) Object {
135+
res := GetAttrOrNil(self, key)
136+
if res == nil {
137+
// FIXME should be AttributeError
138+
panic(fmt.Sprintf("AttributeError: '%s' has no attribute '%s'", self.Type().Name, key))
139+
}
140+
return res
141+
}
142+
143+
// GetAttr
144+
func GetAttr(self Object, keyObj Object) Object {
145+
if key, ok := keyObj.(String); ok {
146+
return GetAttrString(self, string(key))
147+
}
148+
// FIXME should be TypeError
149+
panic(fmt.Sprintf("TypeError: attribute name must be string, not '%s'", self.Type().Name))
150+
}

py/type.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,10 +324,14 @@ func (t *Type) Lookup(name string) Object {
324324

325325
// Get an attribute from the type
326326
//
327+
// Doesn't call __getattr__ etc
328+
//
329+
// Returns nil if not found
330+
//
327331
// FIXME this isn't totally correct!
328332
// as we are ignoring getattribute etc
329333
// See _PyObject_GenericGetAttrWithDict in object.c
330-
func (t *Type) GetMethod(name string) Object {
334+
func (t *Type) GetAttrOrNil(name string) Object {
331335
// Look in instance dictionary first
332336
if res, ok := t.Dict[name]; ok {
333337
return res
@@ -336,6 +340,7 @@ func (t *Type) GetMethod(name string) Object {
336340
if res, ok := t.Type().Dict[name]; ok {
337341
return res
338342
}
343+
// Now look through base classes etc
339344
return t.Lookup(name)
340345
}
341346

@@ -347,7 +352,7 @@ func (t *Type) GetMethod(name string) Object {
347352
//
348353
// May raise exceptions if calling the method failed
349354
func (t *Type) CallMethod(name string, args Tuple, kwargs StringDict) (Object, bool) {
350-
fn := t.GetMethod(name)
355+
fn := t.GetAttrOrNil(name) // FIXME this should use py.GetAttrOrNil?
351356
if fn == nil {
352357
return nil, false
353358
}

vm/eval.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -557,7 +557,7 @@ func do_BUILD_MAP(vm *Vm, count int32) {
557557

558558
// Replaces TOS with getattr(TOS, co_names[namei]).
559559
func do_LOAD_ATTR(vm *Vm, namei int32) {
560-
vm.NotImplemented("LOAD_ATTR", namei)
560+
vm.SET_TOP(py.GetAttrString(vm.TOP(), vm.frame.Code.Names[namei]))
561561
}
562562

563563
// Performs a Boolean operation. The operation name can be found in

0 commit comments

Comments
 (0)