Skip to content

Commit e1f0bbd

Browse files
committed
Make bound methods for built in types work properly
1 parent 4dedb41 commit e1f0bbd

File tree

5 files changed

+76
-2
lines changed

5 files changed

+76
-2
lines changed

notes.txt

+35
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,38 @@ Introspect methods by looking at all public methods
111111
Transform the names, so that initial "M__" becomes "__" then lowercase
112112
the method. Only if the method matches one of the defined function types will it be exported.
113113
FIXME meta data for help would be nice? How attache metadata to go function?
114+
115+
Introspection idea
116+
==================
117+
118+
var method string
119+
if strings.HasPrefix(key, "_") {
120+
method = "M" + key
121+
} else {
122+
method = strings.Title(key)
123+
}
124+
fmt.Printf("*** looking for method %q (key %q)\n", method, key)
125+
r := reflect.TypeOf(self)
126+
if m, ok := r.MethodByName(method); ok {
127+
fmt.Printf("*** m = %#v\n", m.Func)
128+
fmt.Printf("*** type = %#v\n", m.Func.Type())
129+
130+
var fptr func(Object) Object
131+
132+
// fptr is a pointer to a function.
133+
// Obtain the function value itself (likely nil) as a reflect.Value
134+
// so that we can query its type and then set the value.
135+
fn := reflect.ValueOf(fptr).Elem()
136+
137+
// Make a function of the right type.
138+
v := reflect.MakeFunc(fn.Type(), m.Func)
139+
140+
// Assign it to the value fn represents.
141+
fn.Set(v)
142+
143+
fmt.Printf("fptr = %v\n", fptr)
144+
145+
} else {
146+
fmt.Printf("*** method not found\n")
147+
}
148+

py/boundmethod.go

+10
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@ func NewBoundMethod(self, method Object) *BoundMethod {
2424

2525
// Call the bound method
2626
func (bm *BoundMethod) M__call__(args Tuple, kwargs StringDict) Object {
27+
// Call built in methods slightly differently
28+
// FIXME not sure this is sensible! something is wrong with the call interface
29+
// as we aren't sure whether to call it with a self or not
30+
if m, ok := bm.Method.(*Method); ok {
31+
if kwargs != nil {
32+
return m.CallWithKeywords(bm.Self, args, kwargs)
33+
} else {
34+
return m.Call(bm.Self, args)
35+
}
36+
}
2737
newArgs := make(Tuple, len(args)+1)
2838
newArgs[0] = bm.Self
2939
copy(newArgs[1:], args)

py/internal.go

+5
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ func GetAttrOrNil(self Object, key string) (res Object) {
150150
goto found
151151
}
152152
} else {
153+
// Now look in type's dictionary etc
154+
res = self.Type().NativeGetAttrOrNil(key)
155+
if res != nil {
156+
goto found
157+
}
153158
// FIXME introspection for M__methods__ on non *Type objects
154159
}
155160

py/method.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ type Method struct {
6464
Doc string
6565
// Flags - see METH_* flags
6666
Flags int
67-
// C function implementation
67+
// Go function implementation
6868
method interface{}
6969
}
7070

@@ -109,9 +109,10 @@ func (m *Method) Call(self Object, args Tuple) Object {
109109
}
110110
return f(self)
111111
case func(Object, Object) Object:
112+
fmt.Printf("*** CALL %v %v\n", self, args)
112113
if len(args) != 1 {
113114
// FIXME type error
114-
panic(fmt.Sprintf("TypeError: %s() takes exactly 1 argument (%d given)", m.Name, len(args)))
115+
panic(fmt.Sprintf("FOO TypeError: %s() takes exactly 1 argument (%d given)", m.Name, len(args)))
115116
}
116117
return f(self, args[0])
117118
}

py/type.go

+23
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ func NewType(Name string, Doc string) *Type {
204204
ObjectType: TypeType,
205205
Name: Name,
206206
Doc: Doc,
207+
Dict: StringDict{},
207208
}
208209
//t.Ready()
209210
return t
@@ -219,6 +220,7 @@ func NewTypeX(Name string, Doc string, New NewFunc, Init InitFunc) *Type {
219220
Doc: Doc,
220221
New: New,
221222
Init: Init,
223+
Dict: StringDict{},
222224
}
223225
//t.Ready()
224226
return t
@@ -243,6 +245,7 @@ func (t *Type) NewTypeFlags(Name string, Doc string, New NewFunc, Init InitFunc,
243245
New: New,
244246
Init: Init,
245247
Flags: Flags,
248+
Dict: StringDict{},
246249
}
247250
//tt.Ready()
248251
return tt
@@ -386,6 +389,26 @@ func (t *Type) Lookup(name string) Object {
386389
return res
387390
}
388391

392+
// Get an attribute from the type of a go type
393+
//
394+
// Doesn't call __getattr__ etc
395+
//
396+
// Returns nil if not found
397+
//
398+
// Doesn't look in the instance dictionary
399+
//
400+
// FIXME this isn't totally correct!
401+
// as we are ignoring getattribute etc
402+
// See _PyObject_GenericGetAttrWithDict in object.c
403+
func (t *Type) NativeGetAttrOrNil(name string) Object {
404+
// Look in type Dict
405+
if res, ok := t.Dict[name]; ok {
406+
return res
407+
}
408+
// Now look through base classes etc
409+
return t.Lookup(name)
410+
}
411+
389412
// Get an attribute from the type
390413
//
391414
// Doesn't call __getattr__ etc

0 commit comments

Comments
 (0)