in starlark/eval.go [1268:1329]
func slice(x, lo, hi, step_ Value) (Value, error) {
sliceable, ok := x.(Sliceable)
if !ok {
return nil, fmt.Errorf("invalid slice operand %s", x.Type())
}
n := sliceable.Len()
step := 1
if step_ != None {
var err error
step, err = AsInt32(step_)
if err != nil {
return nil, fmt.Errorf("invalid slice step: %s", err)
}
if step == 0 {
return nil, fmt.Errorf("zero is not a valid slice step")
}
}
// TODO(adonovan): opt: preallocate result array.
var start, end int
if step > 0 {
// positive stride
// default indices are [0:n].
var err error
start, end, err = indices(lo, hi, n)
if err != nil {
return nil, err
}
if end < start {
end = start // => empty result
}
} else {
// negative stride
// default indices are effectively [n-1:-1], though to
// get this effect using explicit indices requires
// [n-1:-1-n:-1] because of the treatment of -ve values.
start = n - 1
if err := asIndex(lo, n, &start); err != nil {
return nil, fmt.Errorf("invalid start index: %s", err)
}
if start >= n {
start = n - 1
}
end = -1
if err := asIndex(hi, n, &end); err != nil {
return nil, fmt.Errorf("invalid end index: %s", err)
}
if end < -1 {
end = -1
}
if start < end {
start = end // => empty result
}
}
return sliceable.Slice(start, end, step), nil
}