in starlark/library.go [690:755]
func minmax(thread *Thread, b *Builtin, args Tuple, kwargs []Tuple) (Value, error) {
if len(args) == 0 {
return nil, fmt.Errorf("%s requires at least one positional argument", b.Name())
}
var keyFunc Callable
if err := UnpackArgs(b.Name(), nil, kwargs, "key?", &keyFunc); err != nil {
return nil, err
}
var op syntax.Token
if b.Name() == "max" {
op = syntax.GT
} else {
op = syntax.LT
}
var iterable Value
if len(args) == 1 {
iterable = args[0]
} else {
iterable = args
}
iter := Iterate(iterable)
if iter == nil {
return nil, fmt.Errorf("%s: %s value is not iterable", b.Name(), iterable.Type())
}
defer iter.Done()
var extremum Value
if !iter.Next(&extremum) {
return nil, nameErr(b, "argument is an empty sequence")
}
var extremeKey Value
var keyargs Tuple
if keyFunc == nil {
extremeKey = extremum
} else {
keyargs = Tuple{extremum}
res, err := Call(thread, keyFunc, keyargs, nil)
if err != nil {
return nil, err // to preserve backtrace, don't modify error
}
extremeKey = res
}
var x Value
for iter.Next(&x) {
var key Value
if keyFunc == nil {
key = x
} else {
keyargs[0] = x
res, err := Call(thread, keyFunc, keyargs, nil)
if err != nil {
return nil, err // to preserve backtrace, don't modify error
}
key = res
}
if ok, err := Compare(op, key, extremeKey); err != nil {
return nil, nameErr(b, err)
} else if ok {
extremum = x
extremeKey = key
}
}
return extremum, nil
}