262 lines
4.6 KiB
Go
262 lines
4.6 KiB
Go
// 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
|
|
}
|