Commit db97d4f4 authored by ns-cweber's avatar ns-cweber Committed by Dylan Trotter

Issue #12: Fix native attribute access (#41)

* Implemented via descriptors instead of overriding GetAttribute
parent b0e8553c
......@@ -64,10 +64,10 @@ func toNativeMetaclassUnsafe(o *Object) *nativeMetaclass {
return (*nativeMetaclass)(o.toPointer())
}
func newNativeType(rtype reflect.Type, base *Type, d *Dict) *nativeMetaclass {
func newNativeType(rtype reflect.Type, base *Type) *nativeMetaclass {
return &nativeMetaclass{
Type{
Object: Object{typ: nativeMetaclassType, dict: d},
Object: Object{typ: nativeMetaclassType},
name: nativeTypeName(rtype),
basis: base.basis,
bases: []*Type{base},
......@@ -337,7 +337,21 @@ func getNativeType(rtype reflect.Type) *Type {
d[meth.Name] = newNativeMethod(meth.Name, meth.Func)
}
}
t = &newNativeType(rtype, base, newStringDict(d)).Type
t = &newNativeType(rtype, base).Type
derefed := rtype
for derefed.Kind() == reflect.Ptr {
derefed = derefed.Elem()
}
if derefed.Kind() == reflect.Struct {
for i := 0; i < derefed.NumField(); i++ {
name := derefed.Field(i).Name
d[name] = newNativeField(name, i, t)
}
}
t.dict = newStringDict(d)
// This cannot fail since we're defining simple classes.
if err := prepareType(t); err != "" {
logFatal(err)
......@@ -348,6 +362,21 @@ func getNativeType(rtype reflect.Type) *Type {
return t
}
func newNativeField(name string, i int, t *Type) *Object {
nativeFieldGet := func(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) {
if raised := checkFunctionArgs(f, name, args, t); raised != nil {
return nil, raised
}
v := toNativeUnsafe(args[0]).value
for v.Type().Kind() == reflect.Ptr {
v = v.Elem()
}
return WrapNative(f, v.Field(i))
}
get := newBuiltinFunction(name, nativeFieldGet).ToObject()
return newProperty(get, nil, nil).ToObject()
}
func newNativeMethod(name string, fun reflect.Value) *Object {
return newBuiltinFunction(name, func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) {
return nativeInvoke(f, fun, args)
......
......@@ -24,7 +24,7 @@ import (
func TestNativeMetaclassNew(t *testing.T) {
var i int16
intType := &newNativeType(reflect.TypeOf(i), IntType, NewDict()).Type
intType := &newNativeType(reflect.TypeOf(i), IntType).Type
fun := wrapFuncForTest(func(f *Frame, args ...*Object) *BaseException {
newFunc, raised := GetAttr(f, intType.ToObject(), NewStr("new"), nil)
if raised != nil {
......@@ -413,6 +413,33 @@ func TestNativeTypeName(t *testing.T) {
}
}
func TestNewNativeFieldChecksInstanceType(t *testing.T) {
f := newFrame(nil)
// Given a native object
native, raised := WrapNative(f, reflect.ValueOf(struct{ foo string }{}))
if raised != nil {
t.Fatal("Unexpected exception:", raised)
}
// When its field property is assigned to a different type
property, raised := native.typ.dict.GetItemString(f, "foo")
if raised != nil {
t.Fatal("Unexpected exception:", raised)
}
if raised := IntType.dict.SetItemString(f, "foo", property); raised != nil {
t.Fatal("Unexpected exception:", raised)
}
// And we try to access that property on an object of the new type
_, raised = GetAttr(f, NewInt(1).ToObject(), NewStr("foo"), nil)
// Then expect a TypeError was raised
if raised == nil || raised.Type() != TypeErrorType {
t.Fatal("Wanted TypeError; got:", raised)
}
}
func wrapArgs(elems ...interface{}) Args {
f := NewRootFrame()
argc := len(elems)
......
......@@ -16,6 +16,9 @@
from __go__.math import MaxInt32, Pow10, Signbit
from __go__.strings import Count, IndexAny, Repeat
from __go__.encoding.csv import NewReader as NewCSVReader
from __go__.image import Pt
from __go__.strings import NewReader as NewStringReader
assert Count('foo,bar,baz', ',') == 2
assert IndexAny('foobar', 'obr') == 1
......@@ -23,3 +26,10 @@ assert Repeat('foo', 3) == 'foofoofoo'
assert MaxInt32 == 2147483647
assert Pow10(2.0) == 100.0
assert Signbit(-42.0) == True # pylint: disable=g-explicit-bool-comparison
# Can access field on unreferenced struct (Pt returns an image.Point struct)
assert Pt(1, 0).X == 1
# Can access field on pointer to struct (NewCSVReader returns a pointer to a
# csv.Reader struct)
assert NewCSVReader(NewStringReader("foo")).LazyQuotes == False
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment