github.com/google/grumpy@v0.0.0-20171122020858-3ec87959189c/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  }