func evalSubscript(ec *evalCtx, left, right Value, lp, rp parse.Pos) Value { var sub string if s, ok := right.(str); ok { sub = string(s) } else { ec.errorf(rp, "right operand of subscript must be of type string") } switch left.(type) { case *table: t := left.(*table) // TODO(xiaq): An index is considered a list index if it can be parsed // as an unsigned integer; otherwise it is a dict index. This is // somewhat subtle. idx, err := strconv.ParseUint(sub, 10, 0) if err == nil { if idx < uint64(len(t.List)) { return t.List[idx] } ec.errorf(rp, "index out of range") } if v, ok := t.Dict[sub]; ok { return v } ec.errorf(rp, "nonexistent key %q", sub) return nil case str: invalidIndex := "invalid index, must be integer or integer:integer" ss := strings.Split(sub, ":") if len(ss) > 2 { ec.errorf(rp, invalidIndex) } idx := make([]int, len(ss)) for i, s := range ss { n, err := strconv.ParseInt(s, 10, 0) if err != nil { ec.errorf(rp, invalidIndex) } idx[i] = int(n) } var s string var e error if len(idx) == 1 { var r rune r, e = strutil.NthRune(toString(left), idx[0]) s = string(r) } else { s, e = strutil.SubstringByRune(toString(left), idx[0], idx[1]) } if e != nil { ec.errorf(rp, "%v", e) } return str(s) default: ec.errorf(lp, "left operand of subscript must be of type string, env, table or any") return nil } }
func (s String) Index(idx Value) Value { i := intIndex(idx) r, err := strutil.NthRune(string(s), i) maybeThrow(err) return String(string(r)) }