github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/runtime/slots.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 "strings" 21 ) 22 23 var ( 24 slotsType = reflect.TypeOf(typeSlots{}) 25 numSlots = slotsType.NumField() 26 slotNames = calcSlotNames() 27 ) 28 29 type slot interface { 30 // makeCallable returns a new callable object that forwards calls to 31 // the receiving slot with the given slotName. It is used to populate 32 // t's type dictionary so that slots are accessible from Python. 33 makeCallable(t *Type, slotName string) *Object 34 // wrapCallable updates the receiver slot to forward its calls to the 35 // given callable. This method is called when a user defined type 36 // defines a slot method in Python to override the slot. 37 wrapCallable(callable *Object) bool 38 } 39 40 type basisSlot struct { 41 Fn func(*Object) reflect.Value 42 } 43 44 func (s *basisSlot) makeCallable(t *Type, slotName string) *Object { 45 return nil 46 } 47 48 func (s *basisSlot) wrapCallable(callable *Object) bool { 49 return false 50 } 51 52 type binaryOpFunc func(*Frame, *Object, *Object) (*Object, *BaseException) 53 54 type binaryOpSlot struct { 55 Fn binaryOpFunc 56 } 57 58 func (s *binaryOpSlot) makeCallable(t *Type, slotName string) *Object { 59 return newBuiltinFunction(slotName, func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 60 if raised := checkMethodArgs(f, slotName, args, t, ObjectType); raised != nil { 61 return nil, raised 62 } 63 return s.Fn(f, args[0], args[1]) 64 }).ToObject() 65 } 66 67 func (s *binaryOpSlot) wrapCallable(callable *Object) bool { 68 s.Fn = func(f *Frame, v, w *Object) (*Object, *BaseException) { 69 return callable.Call(f, Args{v, w}, nil) 70 } 71 return true 72 } 73 74 type callSlot struct { 75 Fn func(*Frame, *Object, Args, KWArgs) (*Object, *BaseException) 76 } 77 78 func (s *callSlot) makeCallable(t *Type, _ string) *Object { 79 return newBuiltinFunction("__call__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 80 if raised := checkMethodVarArgs(f, "__call__", args, t); raised != nil { 81 return nil, raised 82 } 83 return t.slots.Call.Fn(f, args[0], args[1:], kwargs) 84 }).ToObject() 85 } 86 87 func (s *callSlot) wrapCallable(callable *Object) bool { 88 s.Fn = func(f *Frame, o *Object, args Args, kwargs KWArgs) (*Object, *BaseException) { 89 callArgs := make(Args, len(args)+1) 90 callArgs[0] = o 91 copy(callArgs[1:], args) 92 return callable.Call(f, callArgs, kwargs) 93 } 94 return true 95 } 96 97 type delAttrSlot struct { 98 Fn func(*Frame, *Object, *Str) *BaseException 99 } 100 101 func (s *delAttrSlot) makeCallable(t *Type, slotName string) *Object { 102 return newBuiltinFunction(slotName, func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 103 if raised := checkMethodArgs(f, slotName, args, t, StrType); raised != nil { 104 return nil, raised 105 } 106 if raised := s.Fn(f, args[0], toStrUnsafe(args[1])); raised != nil { 107 return nil, raised 108 } 109 return None, nil 110 }).ToObject() 111 } 112 113 func (s *delAttrSlot) wrapCallable(callable *Object) bool { 114 s.Fn = func(f *Frame, o *Object, name *Str) *BaseException { 115 _, raised := callable.Call(f, Args{o, name.ToObject()}, nil) 116 return raised 117 } 118 return true 119 } 120 121 type deleteSlot struct { 122 Fn func(*Frame, *Object, *Object) *BaseException 123 } 124 125 func (s *deleteSlot) makeCallable(t *Type, slotName string) *Object { 126 return newBuiltinFunction(slotName, func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 127 if raised := checkMethodArgs(f, slotName, args, t, ObjectType); raised != nil { 128 return nil, raised 129 } 130 if raised := s.Fn(f, args[0], args[1]); raised != nil { 131 return nil, raised 132 } 133 return None, nil 134 }).ToObject() 135 } 136 137 func (s *deleteSlot) wrapCallable(callable *Object) bool { 138 s.Fn = func(f *Frame, desc *Object, inst *Object) *BaseException { 139 _, raised := callable.Call(f, Args{desc, inst}, nil) 140 return raised 141 } 142 return true 143 } 144 145 type delItemSlot struct { 146 Fn func(*Frame, *Object, *Object) *BaseException 147 } 148 149 func (s *delItemSlot) makeCallable(t *Type, slotName string) *Object { 150 return newBuiltinFunction(slotName, func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 151 if raised := checkMethodArgs(f, slotName, args, t, ObjectType); raised != nil { 152 return nil, raised 153 } 154 if raised := s.Fn(f, args[0], args[1]); raised != nil { 155 return nil, raised 156 } 157 return None, nil 158 }).ToObject() 159 } 160 161 func (s *delItemSlot) wrapCallable(callable *Object) bool { 162 s.Fn = func(f *Frame, o *Object, key *Object) *BaseException { 163 _, raised := callable.Call(f, Args{o, key}, nil) 164 return raised 165 } 166 return true 167 } 168 169 type getAttributeSlot struct { 170 Fn func(*Frame, *Object, *Str) (*Object, *BaseException) 171 } 172 173 func (s *getAttributeSlot) makeCallable(t *Type, slotName string) *Object { 174 return newBuiltinFunction(slotName, func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 175 if raised := checkMethodArgs(f, slotName, args, t, StrType); raised != nil { 176 return nil, raised 177 } 178 return s.Fn(f, args[0], toStrUnsafe(args[1])) 179 }).ToObject() 180 } 181 182 func (s *getAttributeSlot) wrapCallable(callable *Object) bool { 183 s.Fn = func(f *Frame, o *Object, name *Str) (*Object, *BaseException) { 184 return callable.Call(f, Args{o, name.ToObject()}, nil) 185 } 186 return true 187 } 188 189 type getSlot struct { 190 Fn func(*Frame, *Object, *Object, *Type) (*Object, *BaseException) 191 } 192 193 func (s *getSlot) makeCallable(t *Type, slotName string) *Object { 194 return newBuiltinFunction(slotName, func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 195 if raised := checkMethodArgs(f, slotName, args, t, ObjectType, TypeType); raised != nil { 196 return nil, raised 197 } 198 return s.Fn(f, args[0], args[1], toTypeUnsafe(args[2])) 199 }).ToObject() 200 } 201 202 func (s *getSlot) wrapCallable(callable *Object) bool { 203 s.Fn = func(f *Frame, desc, inst *Object, owner *Type) (*Object, *BaseException) { 204 return callable.Call(f, Args{desc, inst, owner.ToObject()}, nil) 205 } 206 return true 207 } 208 209 type initSlot struct { 210 Fn func(*Frame, *Object, Args, KWArgs) (*Object, *BaseException) 211 } 212 213 func (s *initSlot) makeCallable(t *Type, _ string) *Object { 214 return newBuiltinFunction("__init__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 215 if raised := checkMethodVarArgs(f, "__init__", args, t); raised != nil { 216 return nil, raised 217 } 218 return t.slots.Init.Fn(f, args[0], args[1:], kwargs) 219 }).ToObject() 220 } 221 222 func (s *initSlot) wrapCallable(callable *Object) bool { 223 s.Fn = func(f *Frame, o *Object, args Args, kwargs KWArgs) (*Object, *BaseException) { 224 callArgs := make(Args, len(args)+1) 225 callArgs[0] = o 226 copy(callArgs[1:], args) 227 return callable.Call(f, callArgs, kwargs) 228 } 229 return true 230 } 231 232 type nativeSlot struct { 233 Fn func(*Frame, *Object) (reflect.Value, *BaseException) 234 } 235 236 func (s *nativeSlot) makeCallable(t *Type, slotName string) *Object { 237 return nil 238 } 239 240 func (s *nativeSlot) wrapCallable(callable *Object) bool { 241 return false 242 } 243 244 type newSlot struct { 245 Fn func(*Frame, *Type, Args, KWArgs) (*Object, *BaseException) 246 } 247 248 func (s *newSlot) makeCallable(t *Type, _ string) *Object { 249 return newStaticMethod(newBuiltinFunction("__new__", func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 250 if raised := checkFunctionVarArgs(f, "__new__", args, TypeType); raised != nil { 251 return nil, raised 252 } 253 typeArg := toTypeUnsafe(args[0]) 254 if !typeArg.isSubclass(t) { 255 format := "%[1]s.__new__(%[2]s): %[2]s is not a subtype of %[1]s" 256 return nil, f.RaiseType(TypeErrorType, fmt.Sprintf(format, t.Name(), typeArg.Name())) 257 } 258 return t.slots.New.Fn(f, typeArg, args[1:], kwargs) 259 }).ToObject()).ToObject() 260 } 261 262 func (s *newSlot) wrapCallable(callable *Object) bool { 263 s.Fn = func(f *Frame, t *Type, args Args, kwargs KWArgs) (*Object, *BaseException) { 264 callArgs := make(Args, len(args)+1) 265 callArgs[0] = t.ToObject() 266 copy(callArgs[1:], args) 267 return callable.Call(f, callArgs, kwargs) 268 } 269 return true 270 } 271 272 type setAttrSlot struct { 273 Fn func(*Frame, *Object, *Str, *Object) *BaseException 274 } 275 276 func (s *setAttrSlot) makeCallable(t *Type, slotName string) *Object { 277 return newBuiltinFunction(slotName, func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 278 if raised := checkMethodArgs(f, slotName, args, t, StrType, ObjectType); raised != nil { 279 return nil, raised 280 } 281 if raised := s.Fn(f, args[0], toStrUnsafe(args[1]), args[2]); raised != nil { 282 return nil, raised 283 } 284 return None, nil 285 }).ToObject() 286 } 287 288 func (s *setAttrSlot) wrapCallable(callable *Object) bool { 289 s.Fn = func(f *Frame, o *Object, name *Str, value *Object) *BaseException { 290 _, raised := callable.Call(f, Args{o, name.ToObject(), value}, nil) 291 return raised 292 } 293 return true 294 } 295 296 type setItemSlot struct { 297 Fn func(*Frame, *Object, *Object, *Object) *BaseException 298 } 299 300 func (s *setItemSlot) makeCallable(t *Type, slotName string) *Object { 301 return newBuiltinFunction(slotName, func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 302 if raised := checkMethodArgs(f, slotName, args, t, ObjectType, ObjectType); raised != nil { 303 return nil, raised 304 } 305 if raised := s.Fn(f, args[0], args[1], args[2]); raised != nil { 306 return nil, raised 307 } 308 return None, nil 309 }).ToObject() 310 } 311 312 func (s *setItemSlot) wrapCallable(callable *Object) bool { 313 s.Fn = func(f *Frame, o *Object, key *Object, value *Object) *BaseException { 314 _, raised := callable.Call(f, Args{o, key, value}, nil) 315 return raised 316 } 317 return true 318 } 319 320 type setSlot struct { 321 Fn func(*Frame, *Object, *Object, *Object) *BaseException 322 } 323 324 func (s *setSlot) makeCallable(t *Type, slotName string) *Object { 325 return newBuiltinFunction(slotName, func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 326 if raised := checkMethodArgs(f, slotName, args, t, ObjectType, ObjectType); raised != nil { 327 return nil, raised 328 } 329 if raised := s.Fn(f, args[0], args[1], args[2]); raised != nil { 330 return nil, raised 331 } 332 return None, nil 333 }).ToObject() 334 } 335 336 func (s *setSlot) wrapCallable(callable *Object) bool { 337 s.Fn = func(f *Frame, desc, inst, value *Object) *BaseException { 338 _, raised := callable.Call(f, Args{desc, inst, value}, nil) 339 return raised 340 } 341 return true 342 } 343 344 type unaryOpSlot struct { 345 Fn func(*Frame, *Object) (*Object, *BaseException) 346 } 347 348 func (s *unaryOpSlot) makeCallable(t *Type, slotName string) *Object { 349 return newBuiltinFunction(slotName, func(f *Frame, args Args, kwargs KWArgs) (*Object, *BaseException) { 350 if raised := checkMethodArgs(f, slotName, args, t); raised != nil { 351 return nil, raised 352 } 353 return s.Fn(f, args[0]) 354 }).ToObject() 355 } 356 357 func (s *unaryOpSlot) wrapCallable(callable *Object) bool { 358 s.Fn = func(f *Frame, o *Object) (*Object, *BaseException) { 359 return callable.Call(f, Args{o}, nil) 360 } 361 return true 362 } 363 364 // typeSlots hold a type's special methods such as __eq__. During type 365 // initialization, any field that is not set for that type will be inherited 366 // according to the type's MRO. Therefore, any given field will be nil only if 367 // that method is not defined for the type nor any of its super classes. Each 368 // slot is expected to be a pointer to a struct with a single function field. 369 // The wrapper structs permit comparison of like slots which is occasionally 370 // necessary to determine whether a function has been overridden by a subclass. 371 type typeSlots struct { 372 Abs *unaryOpSlot 373 Add *binaryOpSlot 374 And *binaryOpSlot 375 Basis *basisSlot 376 Call *callSlot 377 Cmp *binaryOpSlot 378 Complex *unaryOpSlot 379 Contains *binaryOpSlot 380 DelAttr *delAttrSlot 381 Delete *deleteSlot 382 DelItem *delItemSlot 383 Div *binaryOpSlot 384 DivMod *binaryOpSlot 385 Eq *binaryOpSlot 386 Float *unaryOpSlot 387 FloorDiv *binaryOpSlot 388 GE *binaryOpSlot 389 Get *getSlot 390 GetAttribute *getAttributeSlot 391 GetItem *binaryOpSlot 392 GT *binaryOpSlot 393 Hash *unaryOpSlot 394 Hex *unaryOpSlot 395 IAdd *binaryOpSlot 396 IAnd *binaryOpSlot 397 IDiv *binaryOpSlot 398 IDivMod *binaryOpSlot 399 IFloorDiv *binaryOpSlot 400 ILShift *binaryOpSlot 401 IMod *binaryOpSlot 402 IMul *binaryOpSlot 403 Index *unaryOpSlot 404 Init *initSlot 405 Int *unaryOpSlot 406 Invert *unaryOpSlot 407 IOr *binaryOpSlot 408 IPow *binaryOpSlot 409 IRShift *binaryOpSlot 410 ISub *binaryOpSlot 411 Iter *unaryOpSlot 412 IXor *binaryOpSlot 413 LE *binaryOpSlot 414 Len *unaryOpSlot 415 Long *unaryOpSlot 416 LShift *binaryOpSlot 417 LT *binaryOpSlot 418 Mod *binaryOpSlot 419 Mul *binaryOpSlot 420 Native *nativeSlot 421 NE *binaryOpSlot 422 Neg *unaryOpSlot 423 New *newSlot 424 Next *unaryOpSlot 425 NonZero *unaryOpSlot 426 Oct *unaryOpSlot 427 Or *binaryOpSlot 428 Pos *unaryOpSlot 429 Pow *binaryOpSlot 430 RAdd *binaryOpSlot 431 RAnd *binaryOpSlot 432 RDiv *binaryOpSlot 433 RDivMod *binaryOpSlot 434 Repr *unaryOpSlot 435 RFloorDiv *binaryOpSlot 436 RLShift *binaryOpSlot 437 RMod *binaryOpSlot 438 RMul *binaryOpSlot 439 ROr *binaryOpSlot 440 RPow *binaryOpSlot 441 RRShift *binaryOpSlot 442 RShift *binaryOpSlot 443 RSub *binaryOpSlot 444 RXor *binaryOpSlot 445 Set *setSlot 446 SetAttr *setAttrSlot 447 SetItem *setItemSlot 448 Str *unaryOpSlot 449 Sub *binaryOpSlot 450 Unicode *unaryOpSlot 451 Xor *binaryOpSlot 452 } 453 454 func calcSlotNames() []string { 455 names := make([]string, numSlots, numSlots) 456 for i := 0; i < numSlots; i++ { 457 field := slotsType.Field(i) 458 name := "" 459 if field.Name == "Next" { 460 name = "next" 461 } else { 462 name = fmt.Sprintf("__%s__", strings.ToLower(field.Name)) 463 } 464 names[i] = name 465 } 466 return names 467 }