diff --git a/builtin-base.go b/builtin-base.go index 45b89ce..acedefa 100644 --- a/builtin-base.go +++ b/builtin-base.go @@ -43,7 +43,7 @@ func isStringFunc(ctx kern.ExprContext, name string, args map[string]any) (resul } func isFractionFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { - result = kern.IsFract(args[kern.ParamValue]) + result = kern.IsFraction(args[kern.ParamValue]) return } diff --git a/helpers.go b/helpers.go index 49922de..cc8df30 100644 --- a/helpers.go +++ b/helpers.go @@ -11,6 +11,7 @@ import ( "strings" "git.portale-stac.it/go-pkg/expr/kern" + "git.portale-stac.it/go-pkg/expr/util" ) func EvalString(ctx kern.ExprContext, source string) (result any, err error) { @@ -38,7 +39,7 @@ func EvalStringA(source string, args ...Arg) (result any, err error) { func EvalStringV(source string, args []Arg) (result any, err error) { ctx := NewSimpleStoreWithoutGlobalContext() for _, arg := range args { - if kern.IsFunc(arg.Value) { + if util.IsFunc(arg.Value) { if f, ok := arg.Value.(kern.FuncTemplate); ok { functor := kern.NewGolangFunctor(f) // ctx.RegisterFunc(arg.Name, functor, 0, -1) diff --git a/import-utils.go b/import-utils.go index 0d0d766..75eddd3 100644 --- a/import-utils.go +++ b/import-utils.go @@ -13,6 +13,7 @@ import ( "strings" "git.portale-stac.it/go-pkg/expr/kern" + "git.portale-stac.it/go-pkg/expr/util" ) const ( @@ -85,7 +86,7 @@ func searchAmongPath(filename string, dirList []string) (filePath string) { } for _, dir := range dirList { - if dir, err = kern.ExpandPath(dir); err != nil { + if dir, err = util.ExpandPath(dir); err != nil { continue } if fullPath := path.Join(dir, filename); isFile(fullPath) { @@ -108,7 +109,7 @@ func isPathRelative(filePath string) bool { } func makeFilepath(filename string, dirList []string) (filePath string, err error) { - if filename, err = kern.ExpandPath(filename); err != nil { + if filename, err = util.ExpandPath(filename); err != nil { return } diff --git a/kern/bool.go b/kern/bool.go new file mode 100644 index 0000000..868d982 --- /dev/null +++ b/kern/bool.go @@ -0,0 +1,27 @@ +// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// string.go +package kern + +func IsBool(v any) (ok bool) { + _, ok = v.(bool) + return ok +} + +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 +} diff --git a/kern/dict-type.go b/kern/dict-type.go index 94c67fe..bfb4473 100644 --- a/kern/dict-type.go +++ b/kern/dict-type.go @@ -12,6 +12,11 @@ import ( type DictType map[any]any +func IsDict(v any) (ok bool) { + _, ok = v.(*DictType) + return ok +} + func MakeDict() (dict *DictType) { d := make(DictType) dict = &d diff --git a/kern/float.go b/kern/float.go new file mode 100644 index 0000000..813e93d --- /dev/null +++ b/kern/float.go @@ -0,0 +1,23 @@ +// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// float.go +package kern + +func IsFloat(v any) (ok bool) { + _, ok = v.(float64) + return ok +} + +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 +} diff --git a/kern/fraction-type.go b/kern/fraction-type.go index 290d402..63ec354 100644 --- a/kern/fraction-type.go +++ b/kern/fraction-type.go @@ -367,3 +367,15 @@ func IsFraction(v any) (ok bool) { _, ok = v.(*FractionType) 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 +} diff --git a/kern/function.go b/kern/function.go index 9cfb948..32a0d51 100644 --- a/kern/function.go +++ b/kern/function.go @@ -14,6 +14,11 @@ type FuncTemplate func(ctx ExprContext, name string, args map[string]any) (resul type DeepFuncTemplate func(a, b any) (eq bool, err error) +func IsFunctor(v any) (ok bool) { + _, ok = v.(Functor) + return +} + // ---- Common functor definition type BaseFunctor struct { info ExprFunc diff --git a/kern/iterator.go b/kern/iterator.go index 207fab1..b61f0a4 100644 --- a/kern/iterator.go +++ b/kern/iterator.go @@ -45,3 +45,8 @@ type ExtIterator interface { func ErrNoOperation(name string) error { return fmt.Errorf("no %s() function defined in the data-source", name) } + +func IsIterator(v any) (ok bool) { + _, ok = v.(Iterator) + return +} diff --git a/kern/list-type.go b/kern/list-type.go index eefbf26..bf23fd3 100644 --- a/kern/list-type.go +++ b/kern/list-type.go @@ -12,6 +12,11 @@ import ( type ListType []any +func IsList(v any) (ok bool) { + _, ok = v.(*ListType) + return ok +} + func NewListA(listAny ...any) (list *ListType) { if listAny == nil { listAny = []any{} diff --git a/kern/number.go b/kern/number.go new file mode 100644 index 0000000..a8c4f00 --- /dev/null +++ b/kern/number.go @@ -0,0 +1,77 @@ +// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// number.go +package kern + +import ( + "fmt" +) + +func IsInteger(v any) (ok bool) { + _, 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 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 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 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 +} diff --git a/kern/string.go b/kern/string.go new file mode 100644 index 0000000..00f48d8 --- /dev/null +++ b/kern/string.go @@ -0,0 +1,23 @@ +// Copyright (c) 2024-2026 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// string.go +package kern + +import ( + "fmt" +) + +func IsString(v any) (ok bool) { + _, ok = v.(string) + return ok +} + +func ToGoString(value any, description string) (s string, err error) { + if s, ok := value.(string); ok { + return s, nil + } else { + err = fmt.Errorf("%s expected string, got %s (%v)", description, TypeName(value), value) + } + return +} diff --git a/kern/utils.go b/kern/utils.go deleted file mode 100644 index 1758bf2..0000000 --- a/kern/utils.go +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). -// All rights reserved. - -// utils.go -package kern - -import ( - "fmt" - "reflect" -) - -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 ToGoString(value any, description string) (s string, err error) { - if s, ok := value.(string); ok { - return s, nil - } else { - err = fmt.Errorf("%s expected string, 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 -} diff --git a/operator-assign.go b/operator-assign.go index 5dcdb4a..492cbb7 100644 --- a/operator-assign.go +++ b/operator-assign.go @@ -6,6 +6,7 @@ package expr import ( "git.portale-stac.it/go-pkg/expr/kern" + "git.portale-stac.it/go-pkg/expr/util" ) //-------- assign term @@ -84,7 +85,7 @@ func evalAssign(ctx kern.ExprContext, opTerm *term) (v any, err error) { if info := functor.GetFunc(); info != nil { ctx.RegisterFunc(leftTerm.Source(), info.Functor(), info.ReturnType(), info.Params()) } else if funcDef, ok := functor.(*exprFunctor); ok { - paramSpecs := kern.ForAll(funcDef.params, func(p kern.ExprFuncParam) kern.ExprFuncParam { return p }) + paramSpecs := util.ForAll(funcDef.params, func(p kern.ExprFuncParam) kern.ExprFuncParam { return p }) ctx.RegisterFunc(leftTerm.Source(), functor, kern.TypeAny, paramSpecs) } else { diff --git a/simple-store.go b/simple-store.go index f5d5768..f72cd9e 100644 --- a/simple-store.go +++ b/simple-store.go @@ -9,6 +9,7 @@ import ( "slices" "git.portale-stac.it/go-pkg/expr/kern" + "git.portale-stac.it/go-pkg/expr/util" // "strings" ) @@ -61,8 +62,8 @@ func (ctx *SimpleStore) GetGlobal() (globalCtx kern.ExprContext) { func (ctx *SimpleStore) Clone() kern.ExprContext { clone := &SimpleStore{ global: ctx.global, - varStore: kern.CloneFilteredMap(ctx.varStore, filterRefName), - funcStore: kern.CloneFilteredMap(ctx.funcStore, filterRefName), + varStore: util.CloneFilteredMap(ctx.varStore, filterRefName), + funcStore: util.CloneFilteredMap(ctx.funcStore, filterRefName), } return clone } @@ -138,7 +139,7 @@ func (ctx *SimpleStore) UnsafeSetVar(varName string, value any) { func (ctx *SimpleStore) SetVar(varName string, value any) { // fmt.Printf("[%p] SetVar(%v, %v)\n", ctx, varName, value) - if allowedValue, ok := kern.FromGenericAny(value); ok { + if allowedValue, ok := util.FromGenericAny(value); ok { ctx.varStore[varName] = allowedValue } else { panic(fmt.Errorf("unsupported type %T of value %v", value, value)) diff --git a/t_utils-unix_test.go b/t_utils-unix_test.go index 75639e6..5d8b6c9 100644 --- a/t_utils-unix_test.go +++ b/t_utils-unix_test.go @@ -12,7 +12,7 @@ import ( "path" "testing" - "git.portale-stac.it/go-pkg/expr/kern" + "git.portale-stac.it/go-pkg/expr/util" ) func TestExpandPathRootOk(t *testing.T) { @@ -21,7 +21,7 @@ func TestExpandPathRootOk(t *testing.T) { // wantErr := errors.New(`test expected string, got list ([])`) wantErr := error(nil) - gotValue, gotErr := kern.ExpandPath(source) + gotValue, gotErr := util.ExpandPath(source) if gotErr != nil && gotErr.Error() != wantErr.Error() { t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`, @@ -38,7 +38,7 @@ func TestExpandPathRootSubDirOk(t *testing.T) { // wantErr := errors.New(`test expected string, got list ([])`) wantErr := error(nil) - gotValue, gotErr := kern.ExpandPath(source) + gotValue, gotErr := util.ExpandPath(source) if gotErr != nil && gotErr.Error() != wantErr.Error() { t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`, @@ -56,7 +56,7 @@ func TestExpandPathUser(t *testing.T) { // wantErr := errors.New(`test expected string, got list ([])`) wantErr := error(nil) - gotValue, gotErr := kern.ExpandPath(source) + gotValue, gotErr := util.ExpandPath(source) if gotErr != nil { t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`, @@ -74,7 +74,7 @@ func TestExpandPathEnv(t *testing.T) { // wantErr := errors.New(`test expected string, got list ([])`) wantErr := error(nil) - gotValue, gotErr := kern.ExpandPath(source) + gotValue, gotErr := util.ExpandPath(source) if gotErr != nil { t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`, @@ -90,7 +90,7 @@ func TestExpandPathErr(t *testing.T) { wantValue := "~fake-user/test" wantErr := errors.New(`user: unknown user fake-user`) - gotValue, gotErr := kern.ExpandPath(source) + gotValue, gotErr := util.ExpandPath(source) if gotErr != nil && gotErr.Error() != wantErr.Error() { t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`, @@ -108,7 +108,7 @@ func TestExpandPathUserErr(t *testing.T) { // wantErr := errors.New(`test expected string, got list ([])`) wantErr := error(nil) - gotValue, gotErr := kern.ExpandPath(source) + gotValue, gotErr := util.ExpandPath(source) if gotErr != nil { t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`, diff --git a/t_utils_test.go b/t_utils_test.go index 79dd4dd..3444103 100644 --- a/t_utils_test.go +++ b/t_utils_test.go @@ -10,6 +10,7 @@ import ( "testing" "git.portale-stac.it/go-pkg/expr/kern" + "git.portale-stac.it/go-pkg/expr/util" ) func TestIsString(t *testing.T) { @@ -161,7 +162,7 @@ func TestAnyInteger(t *testing.T) { func TestCopyMap(t *testing.T) { source := map[string]int{"one": 1, "two": 2, "three": 3} dest := make(map[string]int) - result := kern.CopyMap(dest, source) + result := util.CopyMap(dest, source) if !reflect.DeepEqual(result, source) { t.Errorf("utils.CopyMap() failed") } diff --git a/kern/utils-unix.go b/util/utils-unix.go similarity index 98% rename from kern/utils-unix.go rename to util/utils-unix.go index afd0a35..d1b3728 100644 --- a/kern/utils-unix.go +++ b/util/utils-unix.go @@ -4,7 +4,7 @@ // All rights reserved. // utils-unix.go -package kern +package util import ( "os" diff --git a/kern/utils-windows.go b/util/utils-windows.go similarity index 96% rename from kern/utils-windows.go rename to util/utils-windows.go index efad62b..b8336f4 100644 --- a/kern/utils-windows.go +++ b/util/utils-windows.go @@ -4,7 +4,7 @@ // All rights reserved. // utils-unix.go -package kern +package util import ( "os" diff --git a/util/utils.go b/util/utils.go new file mode 100644 index 0000000..88b3d7b --- /dev/null +++ b/util/utils.go @@ -0,0 +1,79 @@ +// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// utils.go +package util + +import ( + "reflect" + + "git.portale-stac.it/go-pkg/expr/kern" +) + +func IsFunc(v any) bool { + return reflect.TypeOf(v).Kind() == reflect.Func +} + +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 = kern.AnyInteger(v); ok { + return + } + if exprAny, ok = kern.AnyFloat(v); ok { + return + } + if exprAny, ok = v.(*kern.DictType); ok { + return + } + if exprAny, ok = v.(*kern.ListType); ok { + return + } + } + 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 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 +}