in lib/strings.go [797:842]
func (l stringLib) substring(args ...ref.Val) ref.Val {
if len(args) != 3 {
return types.NewErr("no such overload for substring")
}
s, ok := args[0].(types.String)
if !ok {
return types.ValOrErr(s, "no such overload for substring")
}
start, ok := args[1].(types.Int)
if !ok {
return types.ValOrErr(start, "no such overload for substring")
}
if start < 0 {
return types.NewErr("substring: start out of range: %d < 0", start)
}
end, ok := args[2].(types.Int)
if !ok {
return types.ValOrErr(end, "no such overload for substring")
}
if end < start {
return types.NewErr("substring: end out of range: %d < %d", end, start)
}
i, pos, left := 0, 0, -1
for ; pos <= len(s); i++ {
if i == int(start) {
left = pos
}
if i == int(end) {
// TODO: Consider adding a heuristic to decide if the
// substring should be cloned to avoid pinning s.
return types.DefaultTypeAdapter.NativeToValue(s[left:pos])
}
if pos == len(s) {
break
}
r, size := utf8.DecodeRuneInString(string(s[pos:]))
if r == utf8.RuneError {
return types.NewErr("substring: invalid rune at position %d in string: %s", pos, s)
}
pos += size
}
if left == -1 {
return types.NewErr("substring: start out of range: %d > %d", start, i)
}
return types.NewErr("substring: end out of range: %d > %d", end, i)
}