This repository was archived by the owner on Mar 23, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 635
Expand file tree
/
Copy pathdescriptor.go
More file actions
125 lines (112 loc) · 3.91 KB
/
descriptor.go
File metadata and controls
125 lines (112 loc) · 3.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Copyright 2016 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package grumpy
import (
"fmt"
"reflect"
)
// Property represents Python 'property' objects.
type Property struct {
Object
get, set, del *Object
}
func newProperty(get, set, del *Object) *Property {
p := &Property{Object{typ: PropertyType}, get, set, del}
p.self = p
return p
}
func toPropertyUnsafe(o *Object) *Property {
return o.self.(*Property)
}
// ToObject upcasts p to an Object.
func (p *Property) ToObject() *Object {
return &p.Object
}
// PropertyType is the object representing the Python 'property' type.
var PropertyType = newBasisType("property", reflect.TypeOf(Property{}), toPropertyUnsafe, ObjectType)
func initPropertyType(map[string]*Object) {
PropertyType.slots.Delete = &deleteSlot{propertyDelete}
PropertyType.slots.Get = &getSlot{propertyGet}
PropertyType.slots.Init = &initSlot{propertyInit}
PropertyType.slots.Set = &setSlot{propertySet}
}
func propertyDelete(f *Frame, desc, inst *Object) *BaseException {
p := toPropertyUnsafe(desc)
if p.del == nil || p.del == None {
return f.RaiseType(AttributeErrorType, "can't delete attribute")
}
_, raised := p.del.Call(f, Args{inst}, nil)
return raised
}
func propertyGet(f *Frame, desc, instance *Object, _ *Type) (*Object, *BaseException) {
p := toPropertyUnsafe(desc)
if p.get == nil || p.get == None {
return nil, f.RaiseType(AttributeErrorType, "unreadable attribute")
}
return p.get.Call(f, Args{instance}, nil)
}
func propertyInit(f *Frame, o *Object, args Args, _ KWArgs) (*Object, *BaseException) {
expectedTypes := []*Type{ObjectType, ObjectType, ObjectType}
argc := len(args)
if argc < 3 {
expectedTypes = expectedTypes[:argc]
}
if raised := checkFunctionArgs(f, "__init__", args, expectedTypes...); raised != nil {
return nil, raised
}
p := toPropertyUnsafe(o)
if argc > 0 {
p.get = args[0]
}
if argc > 1 {
p.set = args[1]
}
if argc > 2 {
p.del = args[2]
}
return None, nil
}
func propertySet(f *Frame, desc, inst, value *Object) *BaseException {
p := toPropertyUnsafe(desc)
if p.set == nil || p.set == None {
return f.RaiseType(AttributeErrorType, "can't set attribute")
}
_, raised := p.set.Call(f, Args{inst, value}, nil)
return raised
}
// makeStructFieldDescriptor creates a descriptor with a getter that returns
// the field given by fieldName from t's basis structure.
func makeStructFieldDescriptor(t *Type, fieldName, propertyName string) *Object {
field, ok := t.basis.FieldByName(fieldName)
if !ok {
logFatal(fmt.Sprintf("no such field %q for basis %s", fieldName, nativeTypeName(t.basis)))
}
getterFunc := reflect.MakeFunc(reflect.TypeOf(Func(nil)), func(argValues []reflect.Value) []reflect.Value {
f := argValues[0].Interface().(*Frame)
args := argValues[1].Interface().(Args)
var ret *Object
var raised *BaseException
if raised = checkFunctionArgs(f, fieldName, args, ObjectType); raised == nil {
o := args[0]
if !o.isInstance(t) {
format := "descriptor '%s' for '%s' objects doesn't apply to '%s' objects"
raised = f.RaiseType(TypeErrorType, fmt.Sprintf(format, propertyName, t.Name(), o.typ.Name()))
} else {
ret, raised = WrapNative(f, t.slots.Basis.Fn(o).FieldByIndex(field.Index))
}
}
return []reflect.Value{reflect.ValueOf(ret), reflect.ValueOf(raised)}
}).Interface().(Func)
return newProperty(newBuiltinFunction("_get"+fieldName, getterFunc).ToObject(), None, None).ToObject()
}