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