github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/runtime/object.go (about) 1 // Copyright 2016 Google Inc. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package grumpy 16 17 import ( 18 "fmt" 19 "reflect" 20 "sync/atomic" 21 "unsafe" 22 ) 23 24 var ( 25 objectBasis = reflect.TypeOf(Object{}) 26 objectReconstructorFunc = newBuiltinFunction("_reconstructor", objectReconstructor).ToObject() 27 objectReduceFunc = newBuiltinFunction("__reduce__", objectReduce).ToObject() 28 // ObjectType is the object representing the Python 'object' type. 29 // 30 // We don't use newBasisType() here since that introduces an initialization 31 // cycle between TypeType and ObjectType. 32 ObjectType = &Type{ 33 name: "object", 34 basis: objectBasis, 35 flags: typeFlagDefault, 36 slots: typeSlots{Basis: &basisSlot{objectBasisFunc}}, 37 } 38 ) 39 40 // Object represents Python 'object' objects. 41 type Object struct { 42 typ *Type `attr:"__class__"` 43 dict *Dict 44 ref *WeakRef 45 } 46 47 func newObject(t *Type) *Object { 48 var dict *Dict 49 if t != ObjectType { 50 dict = NewDict() 51 } 52 o := (*Object)(unsafe.Pointer(reflect.New(t.basis).Pointer())) 53 o.typ = t 54 o.setDict(dict) 55 return o 56 } 57 58 // Call invokes the callable Python object o with the given positional and 59 // keyword args. args must be non-nil (but can be empty). kwargs can be nil. 60 func (o *Object) Call(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 61 call := o.Type().slots.Call 62 if call == nil { 63 return nil, f.RaiseType(TypeErrorType, fmt.Sprintf("'%s' object is not callable", o.Type().Name())) 64 } 65 return call.Fn(f, o, args, kwargs) 66 } 67 68 // Dict returns o's object dict, aka __dict__. 69 func (o *Object) Dict() *Dict { 70 p := (*unsafe.Pointer)(unsafe.Pointer(&o.dict)) 71 return (*Dict)(atomic.LoadPointer(p)) 72 } 73 74 func (o *Object) setDict(d *Dict) { 75 p := (*unsafe.Pointer)(unsafe.Pointer(&o.dict)) 76 atomic.StorePointer(p, unsafe.Pointer(d)) 77 } 78 79 // String returns a string representation of o, e.g. for debugging. 80 func (o *Object) String() string { 81 if o == nil { 82 return "nil" 83 } 84 s, raised := Repr(NewRootFrame(), o) 85 if raised != nil { 86 return fmt.Sprintf("<%s object (repr raised %s)>", o.typ.Name(), raised.typ.Name()) 87 } 88 return s.Value() 89 } 90 91 // Type returns the Python type of o. 92 func (o *Object) Type() *Type { 93 return o.typ 94 } 95 96 func (o *Object) toPointer() unsafe.Pointer { 97 return unsafe.Pointer(o) 98 } 99 100 func (o *Object) isInstance(t *Type) bool { 101 return o.typ.isSubclass(t) 102 } 103 104 func objectBasisFunc(o *Object) reflect.Value { 105 return reflect.ValueOf(o).Elem() 106 } 107 108 func objectDelAttr(f *Frame, o *Object, name *Str) *BaseException { 109 desc, raised := o.typ.mroLookup(f, name) 110 if raised != nil { 111 return raised 112 } 113 if desc != nil { 114 if del := desc.Type().slots.Delete; del != nil { 115 return del.Fn(f, desc, o) 116 } 117 } 118 deleted := false 119 d := o.Dict() 120 if d != nil { 121 deleted, raised = d.DelItem(f, name.ToObject()) 122 if raised != nil { 123 return raised 124 } 125 } 126 if !deleted { 127 format := "'%s' object has no attribute '%s'" 128 return f.RaiseType(AttributeErrorType, fmt.Sprintf(format, o.typ.Name(), name.Value())) 129 } 130 return nil 131 } 132 133 // objectGetAttribute implements the spec here: 134 // https://docs.python.org/2/reference/datamodel.html#invoking-descriptors 135 func objectGetAttribute(f *Frame, o *Object, name *Str) (*Object, *BaseException) { 136 // Look for a data descriptor in the type. 137 var typeGet *getSlot 138 typeAttr, raised := o.typ.mroLookup(f, name) 139 if raised != nil { 140 return nil, raised 141 } 142 if typeAttr != nil { 143 typeGet = typeAttr.typ.slots.Get 144 if typeGet != nil && (typeAttr.typ.slots.Set != nil || typeAttr.typ.slots.Delete != nil) { 145 return typeGet.Fn(f, typeAttr, o, o.Type()) 146 } 147 } 148 // Look in the object's dict. 149 if d := o.Dict(); d != nil { 150 value, raised := d.GetItem(f, name.ToObject()) 151 if value != nil || raised != nil { 152 return value, raised 153 } 154 } 155 // Use the (non-data) descriptor from the type. 156 if typeGet != nil { 157 return typeGet.Fn(f, typeAttr, o, o.Type()) 158 } 159 // Return the ordinary type attribute. 160 if typeAttr != nil { 161 return typeAttr, nil 162 } 163 format := "'%s' object has no attribute '%s'" 164 return nil, f.RaiseType(AttributeErrorType, fmt.Sprintf(format, o.typ.Name(), name.Value())) 165 } 166 167 func objectHash(f *Frame, o *Object) (*Object, *BaseException) { 168 return NewInt(int(uintptr(o.toPointer()))).ToObject(), nil 169 } 170 171 func objectNew(f *Frame, t *Type, _ Args, _ KWArgs) (*Object, *BaseException) { 172 if t.flags&typeFlagInstantiable == 0 { 173 format := "object.__new__(%s) is not safe, use %s.__new__()" 174 return nil, f.RaiseType(TypeErrorType, fmt.Sprintf(format, t.Name(), t.Name())) 175 } 176 return newObject(t), nil 177 } 178 179 func objectReduce(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 180 expectedTypes := []*Type{ObjectType, IntType} 181 argc := len(args) 182 if argc == 1 { 183 expectedTypes = expectedTypes[:1] 184 } 185 if raised := checkMethodArgs(f, "__reduce__", args, expectedTypes...); raised != nil { 186 return nil, raised 187 } 188 return objectReduceCommon(f, args) 189 } 190 191 func objectReduceEx(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 192 expectedTypes := []*Type{ObjectType, IntType} 193 argc := len(args) 194 if argc == 1 { 195 expectedTypes = expectedTypes[:1] 196 } 197 if raised := checkMethodArgs(f, "__reduce_ex__", args, expectedTypes...); raised != nil { 198 return nil, raised 199 } 200 reduce, raised := args[0].typ.mroLookup(f, NewStr("__reduce__")) 201 if raised != nil { 202 return nil, raised 203 } 204 if reduce != nil && reduce != objectReduceFunc { 205 // __reduce__ is overridden so prefer using it. 206 return reduce.Call(f, args, nil) 207 } 208 return objectReduceCommon(f, args) 209 } 210 211 func objectSetAttr(f *Frame, o *Object, name *Str, value *Object) *BaseException { 212 if typeAttr, raised := o.typ.mroLookup(f, name); raised != nil { 213 return raised 214 } else if typeAttr != nil { 215 if typeSet := typeAttr.typ.slots.Set; typeSet != nil { 216 return typeSet.Fn(f, typeAttr, o, value) 217 } 218 } 219 if d := o.Dict(); d != nil { 220 if raised := d.SetItem(f, name.ToObject(), value); raised == nil || !raised.isInstance(KeyErrorType) { 221 return nil 222 } 223 } 224 return f.RaiseType(AttributeErrorType, fmt.Sprintf("'%s' has no attribute '%s'", o.typ.Name(), name.Value())) 225 } 226 227 func initObjectType(dict map[string]*Object) { 228 ObjectType.typ = TypeType 229 dict["__reduce__"] = objectReduceFunc 230 dict["__reduce_ex__"] = newBuiltinFunction("__reduce_ex__", objectReduceEx).ToObject() 231 dict["__dict__"] = newProperty(newBuiltinFunction("_get_dict", objectGetDict).ToObject(), newBuiltinFunction("_set_dict", objectSetDict).ToObject(), nil).ToObject() 232 ObjectType.slots.DelAttr = &delAttrSlot{objectDelAttr} 233 ObjectType.slots.GetAttribute = &getAttributeSlot{objectGetAttribute} 234 ObjectType.slots.Hash = &unaryOpSlot{objectHash} 235 ObjectType.slots.New = &newSlot{objectNew} 236 ObjectType.slots.SetAttr = &setAttrSlot{objectSetAttr} 237 } 238 239 // objectReconstructor builds an object from a class, its basis type and its 240 // state (e.g. its string or integer value). It is similar to the 241 // copy_reg._reconstructor function in CPython. 242 func objectReconstructor(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 243 if raised := checkFunctionArgs(f, "_reconstructor", args, TypeType, TypeType, ObjectType); raised != nil { 244 return nil, raised 245 } 246 t, basisType, state := toTypeUnsafe(args[0]), toTypeUnsafe(args[1]), args[2] 247 newMethod, raised := GetAttr(f, basisType.ToObject(), NewStr("__new__"), nil) 248 if raised != nil { 249 return nil, raised 250 } 251 o, raised := newMethod.Call(f, Args{t.ToObject(), state}, nil) 252 if raised != nil { 253 return nil, raised 254 } 255 if basisType != ObjectType { 256 initMethod, raised := GetAttr(f, basisType.ToObject(), NewStr("__init__"), None) 257 if raised != nil { 258 return nil, raised 259 } 260 if initMethod != None { 261 if _, raised := initMethod.Call(f, Args{o, state}, nil); raised != nil { 262 return nil, raised 263 } 264 } 265 } 266 return o, nil 267 } 268 269 func objectReduceCommon(f *Frame, args Args) (*Object, *BaseException) { 270 // TODO: Support __getstate__ and __getnewargs__. 271 o := args[0] 272 t := o.Type() 273 proto := 0 274 if len(args) > 1 { 275 proto = toIntUnsafe(args[1]).Value() 276 } 277 var raised *BaseException 278 if proto < 2 { 279 basisType := basisTypes[t.basis] 280 if basisType == t { 281 // Basis types are handled elsewhere by the pickle and 282 // copy frameworks. This matches behavior in 283 // copy_reg._reduce_ex in CPython. 284 return nil, f.RaiseType(TypeErrorType, fmt.Sprintf("can't pickle %s objects", t.Name())) 285 } 286 state := None 287 if basisType != ObjectType { 288 // For subclasses of basis types having state (e.g. 289 // integer values), the state is captured by creating 290 // an instance of that basis type. 291 if state, raised = basisType.Call(f, Args{o}, nil); raised != nil { 292 return nil, raised 293 } 294 } 295 newArgs := NewTuple3(t.ToObject(), basisType.ToObject(), state).ToObject() 296 if d := o.Dict(); d != nil { 297 return NewTuple3(objectReconstructorFunc, newArgs, d.ToObject()).ToObject(), nil 298 } 299 return NewTuple2(objectReconstructorFunc, newArgs).ToObject(), nil 300 } 301 newArgs := []*Object{t.ToObject()} 302 getNewArgsMethod, raised := GetAttr(f, o, NewStr("__getnewargs__"), None) 303 if raised != nil { 304 return nil, raised 305 } 306 if getNewArgsMethod != None { 307 extraNewArgs, raised := getNewArgsMethod.Call(f, nil, nil) 308 if raised != nil { 309 return nil, raised 310 } 311 if !extraNewArgs.isInstance(TupleType) { 312 format := "__getnewargs__ should return a tuple, not '%s'" 313 return nil, f.RaiseType(TypeErrorType, fmt.Sprintf(format, extraNewArgs.Type().Name())) 314 } 315 newArgs = append(newArgs, toTupleUnsafe(extraNewArgs).elems...) 316 } 317 dict := None 318 if d := o.Dict(); d != nil { 319 dict = d.ToObject() 320 } 321 // For proto >= 2 include list and dict items. 322 listItems := None 323 if o.isInstance(ListType) { 324 if listItems, raised = Iter(f, o); raised != nil { 325 return nil, raised 326 } 327 } 328 dictItems := None 329 if o.isInstance(DictType) { 330 iterItems, raised := o.typ.mroLookup(f, NewStr("iteritems")) 331 if raised != nil { 332 return nil, raised 333 } 334 if iterItems != nil { 335 if dictItems, raised = iterItems.Call(f, Args{o}, nil); raised != nil { 336 return nil, raised 337 } 338 } 339 } 340 newFunc, raised := GetAttr(f, t.ToObject(), NewStr("__new__"), nil) 341 if raised != nil { 342 return nil, raised 343 } 344 return NewTuple5(newFunc, NewTuple(newArgs...).ToObject(), dict, listItems, dictItems).ToObject(), nil 345 } 346 347 func objectGetDict(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 348 if raised := checkMethodArgs(f, "_get_dict", args, ObjectType); raised != nil { 349 return nil, raised 350 } 351 o := args[0] 352 d := o.Dict() 353 if d == nil { 354 format := "'%s' object has no attribute '__dict__'" 355 return nil, f.RaiseType(AttributeErrorType, fmt.Sprintf(format, o.typ.Name())) 356 } 357 return args[0].Dict().ToObject(), nil 358 } 359 360 func objectSetDict(f *Frame, args Args, _ KWArgs) (*Object, *BaseException) { 361 if raised := checkMethodArgs(f, "_set_dict", args, ObjectType, DictType); raised != nil { 362 return nil, raised 363 } 364 o := args[0] 365 if o.Type() == ObjectType { 366 format := "'%s' object has no attribute '__dict__'" 367 return nil, f.RaiseType(AttributeErrorType, fmt.Sprintf(format, o.typ.Name())) 368 } 369 o.setDict(toDictUnsafe(args[1])) 370 return None, nil 371 }