github.com/pygolin/runtime@v0.0.0-20201208210830-a62e3cd39798/slice.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 runtime
    16  
    17  import "reflect"
    18  
    19  const errBadSliceIndex = "slice indices must be integers or None or have an __index__ method"
    20  
    21  var (
    22  	// SliceType is the object representing the Python 'slice' type.
    23  	SliceType = newBasisType("slice", reflect.TypeOf(Slice{}), toSliceUnsafe, ObjectType)
    24  )
    25  
    26  // Slice represents Python 'slice' objects.
    27  type Slice struct {
    28  	Object
    29  	start *Object `attr:"start"`
    30  	stop  *Object `attr:"stop"`
    31  	step  *Object `attr:"step"`
    32  }
    33  
    34  func toSliceUnsafe(o *Object) *Slice {
    35  	return (*Slice)(o.toPointer())
    36  }
    37  
    38  // calcSlice returns the three range indices (start, stop, step) and the length
    39  // of the slice produced by slicing a sequence of length numElems by s. As with
    40  // seqRange, the resulting indices can be used to iterate over the slice like:
    41  //
    42  // for i := start; i != stop; i += step { ... }
    43  func (s *Slice) calcSlice(f *Frame, numElems int) (int, int, int, int, *BaseException) {
    44  	step := 1
    45  	if s.step != nil && s.step != None {
    46  		if s.step.typ.slots.Index == nil {
    47  			return 0, 0, 0, 0, f.RaiseType(TypeErrorType, errBadSliceIndex)
    48  		}
    49  		i, raised := IndexInt(f, s.step)
    50  		if raised != nil {
    51  			return 0, 0, 0, 0, raised
    52  		}
    53  		step = i
    54  	}
    55  	var startDef, stopDef int
    56  	if step > 0 {
    57  		startDef, stopDef = 0, numElems
    58  	} else {
    59  		startDef, stopDef = numElems-1, -1
    60  	}
    61  	start, raised := sliceClampIndex(f, s.start, startDef, numElems)
    62  	if raised != nil {
    63  		return 0, 0, 0, 0, raised
    64  	}
    65  	stop, raised := sliceClampIndex(f, s.stop, stopDef, numElems)
    66  	if raised != nil {
    67  		return 0, 0, 0, 0, raised
    68  	}
    69  	stop, sliceLen, result := seqRange(start, stop, step)
    70  	switch result {
    71  	case seqRangeZeroStep:
    72  		return 0, 0, 0, 0, f.RaiseType(ValueErrorType, "slice step cannot be zero")
    73  	case seqRangeOverflow:
    74  		return 0, 0, 0, 0, f.RaiseType(OverflowErrorType, errResultTooLarge)
    75  	}
    76  	return start, stop, step, sliceLen, nil
    77  }
    78  
    79  // ToObject upcasts s to an Object.
    80  func (s *Slice) ToObject() *Object {
    81  	return &s.Object
    82  }
    83  
    84  func sliceEq(f *Frame, v, w *Object) (*Object, *BaseException) {
    85  	return sliceCompare(f, toSliceUnsafe(v), w, Eq)
    86  }
    87  
    88  func sliceGE(f *Frame, v, w *Object) (*Object, *BaseException) {
    89  	return sliceCompare(f, toSliceUnsafe(v), w, GE)
    90  }
    91  
    92  func sliceGT(f *Frame, v, w *Object) (*Object, *BaseException) {
    93  	return sliceCompare(f, toSliceUnsafe(v), w, GT)
    94  }
    95  
    96  func sliceLE(f *Frame, v, w *Object) (*Object, *BaseException) {
    97  	return sliceCompare(f, toSliceUnsafe(v), w, LE)
    98  }
    99  
   100  func sliceLT(f *Frame, v, w *Object) (*Object, *BaseException) {
   101  	return sliceCompare(f, toSliceUnsafe(v), w, LT)
   102  }
   103  
   104  func sliceNE(f *Frame, v, w *Object) (*Object, *BaseException) {
   105  	return sliceCompare(f, toSliceUnsafe(v), w, NE)
   106  }
   107  
   108  func sliceNew(f *Frame, t *Type, args Args, _ KWArgs) (*Object, *BaseException) {
   109  	expectedTypes := []*Type{ObjectType, ObjectType, ObjectType}
   110  	argc := len(args)
   111  	if argc >= 1 && argc <= 3 {
   112  		expectedTypes = expectedTypes[:argc]
   113  	}
   114  	if raised := checkMethodArgs(f, "__new__", args, expectedTypes...); raised != nil {
   115  		return nil, raised
   116  	}
   117  	s := toSliceUnsafe(newObject(t))
   118  	if argc == 1 {
   119  		s.stop = args[0]
   120  	} else {
   121  		s.start = args[0]
   122  		s.stop = args[1]
   123  		if argc > 2 {
   124  			s.step = args[2]
   125  		}
   126  	}
   127  	return s.ToObject(), nil
   128  }
   129  
   130  func sliceRepr(f *Frame, o *Object) (*Object, *BaseException) {
   131  	s := toSliceUnsafe(o)
   132  	elem0, elem1, elem2 := None, s.stop, None
   133  	if s.start != nil {
   134  		elem0 = s.start
   135  	}
   136  	if s.step != nil {
   137  		elem2 = s.step
   138  	}
   139  	r, raised := Repr(f, NewTuple3(elem0, elem1, elem2).ToObject())
   140  	if raised != nil {
   141  		return nil, raised
   142  	}
   143  	return NewStr("slice" + r.Value()).ToObject(), nil
   144  }
   145  
   146  func initSliceType(map[string]*Object) {
   147  	SliceType.flags &^= typeFlagBasetype
   148  	SliceType.slots.Eq = &binaryOpSlot{sliceEq}
   149  	SliceType.slots.GE = &binaryOpSlot{sliceGE}
   150  	SliceType.slots.GT = &binaryOpSlot{sliceGT}
   151  	SliceType.slots.Hash = &unaryOpSlot{hashNotImplemented}
   152  	SliceType.slots.LE = &binaryOpSlot{sliceLE}
   153  	SliceType.slots.LT = &binaryOpSlot{sliceLT}
   154  	SliceType.slots.NE = &binaryOpSlot{sliceNE}
   155  	SliceType.slots.New = &newSlot{sliceNew}
   156  	SliceType.slots.Repr = &unaryOpSlot{sliceRepr}
   157  }
   158  
   159  func sliceClampIndex(f *Frame, index *Object, def, seqLen int) (int, *BaseException) {
   160  	if index == nil || index == None {
   161  		return def, nil
   162  	}
   163  	if index.typ.slots.Index == nil {
   164  		return 0, f.RaiseType(TypeErrorType, errBadSliceIndex)
   165  	}
   166  	i, raised := IndexInt(f, index)
   167  	if raised != nil {
   168  		return 0, raised
   169  	}
   170  	return seqClampIndex(i, seqLen), nil
   171  }
   172  
   173  func sliceCompare(f *Frame, v *Slice, w *Object, cmp binaryOpFunc) (*Object, *BaseException) {
   174  	if !w.isInstance(SliceType) {
   175  		return NotImplemented, nil
   176  	}
   177  	rhs := toSliceUnsafe(w)
   178  	elems1, elems2 := []*Object{None, v.stop, None}, []*Object{None, rhs.stop, None}
   179  	if v.start != nil {
   180  		elems1[0] = v.start
   181  	}
   182  	if v.step != nil {
   183  		elems1[2] = v.step
   184  	}
   185  	if rhs.start != nil {
   186  		elems2[0] = rhs.start
   187  	}
   188  	if rhs.step != nil {
   189  		elems2[2] = rhs.step
   190  	}
   191  	return seqCompare(f, elems1, elems2, cmp)
   192  }