// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // utils.go package expr import ( "fmt" "os" "os/user" "path" "reflect" "strings" ) func IsString(v any) (ok bool) { _, ok = v.(string) return ok } func IsInteger(v any) (ok bool) { _, ok = v.(int64) return ok } func IsFloat(v any) (ok bool) { _, ok = v.(float64) return ok } func IsBool(v any) (ok bool) { _, ok = v.(bool) return ok } func IsList(v any) (ok bool) { _, ok = v.(*ListType) return ok } func IsDict(v any) (ok bool) { _, ok = v.(*DictType) return ok } func IsFract(v any) (ok bool) { _, ok = v.(*FractionType) return ok } func IsRational(v any) (ok bool) { if _, ok = v.(*FractionType); !ok { _, ok = v.(int64) } return ok } func IsNumber(v any) (ok bool) { return IsFloat(v) || IsInteger(v) } func isNumOrFract(v any) (ok bool) { return IsFloat(v) || IsInteger(v) || isFraction(v) } func isNumberString(v any) (ok bool) { return IsString(v) || IsNumber(v) } func isFunctor(v any) (ok bool) { _, ok = v.(Functor) return } func isIterator(v any) (ok bool) { _, ok = v.(Iterator) return } func numAsFloat(v any) (f float64) { var ok bool if f, ok = v.(float64); !ok { if fract, ok := v.(*FractionType); ok { f = fract.toFloat() } else { i, _ := v.(int64) f = float64(i) } } return } func ToBool(v any) (b bool, ok bool) { ok = true switch x := v.(type) { case string: b = len(x) > 0 case float64: b = x != 0.0 case int64: b = x != 0 case bool: b = x default: ok = false } return } func isFunc(v any) bool { return reflect.TypeOf(v).Kind() == reflect.Func } func anyInteger(v any) (i int64, ok bool) { ok = true switch intval := v.(type) { case int: i = int64(intval) case uint8: i = int64(intval) case uint16: i = int64(intval) case uint64: i = int64(intval) case uint32: i = int64(intval) case int8: i = int64(intval) case int16: i = int64(intval) case int32: i = int64(intval) case int64: i = intval default: ok = false } return } func fromGenericAny(v any) (exprAny any, ok bool) { if v != nil { if exprAny, ok = v.(bool); ok { return } if exprAny, ok = v.(string); ok { return } if exprAny, ok = anyInteger(v); ok { return } if exprAny, ok = anyFloat(v); ok { return } if exprAny, ok = v.(*DictType); ok { return } if exprAny, ok = v.(*ListType); ok { return } } return } func anyFloat(v any) (float float64, ok bool) { ok = true switch floatval := v.(type) { case float32: float = float64(floatval) case float64: float = floatval default: ok = false } return } func CopyMap[K comparable, V any](dest, source map[K]V) map[K]V { for k, v := range source { dest[k] = v } return dest } // func CloneMap[K comparable, V any](source map[K]V) map[K]V { // dest := make(map[K]V, len(source)) // return CopyMap(dest, source) // } func CopyFilteredMap[K comparable, V any](dest, source map[K]V, filter func(key K) (accept bool)) map[K]V { // fmt.Printf("--- Clone with filter %p\n", filter) if filter == nil { return CopyMap(dest, source) } else { for k, v := range source { if filter(k) { // fmt.Printf("\tClone var %q\n", k) dest[k] = v } } } return dest } func CloneFilteredMap[K comparable, V any](source map[K]V, filter func(key K) (accept bool)) map[K]V { dest := make(map[K]V, len(source)) return CopyFilteredMap(dest, source, filter) } func ToGoInt(value any, description string) (i int, err error) { if valueInt64, ok := value.(int64); ok { i = int(valueInt64) } else if valueInt, ok := value.(int); ok { i = valueInt } else { err = fmt.Errorf("%s expected integer, got %s (%v)", description, TypeName(value), value) } return } func ForAll[T, V any](ts []T, fn func(T) V) []V { result := make([]V, len(ts)) for i, t := range ts { result[i] = fn(t) } return result } func ExpandPath(sourcePath string) (expandedPath string, err error) { for expandedPath = os.ExpandEnv(sourcePath); expandedPath != sourcePath; expandedPath = os.ExpandEnv(sourcePath) { sourcePath = expandedPath } if strings.HasPrefix(sourcePath, "~") { var home, userName, remainder string slashPos := strings.IndexRune(sourcePath, '/') if slashPos > 0 { userName = sourcePath[1:slashPos] remainder = sourcePath[slashPos:] } else { userName = sourcePath[1:] } if len(userName) == 0 { home, err = os.UserHomeDir() if err != nil { return } } else { var userInfo *user.User userInfo, err = user.Lookup(userName) if err != nil { return } home = userInfo.HomeDir } expandedPath = path.Join(home, remainder) } return }