// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). // All rights reserved. // builtin-base.go package expr import ( "fmt" "math" "strconv" "strings" "git.portale-stac.it/go-pkg/expr/kern" ) const ( ParamDenominator = "denominator" ) func isNilFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { result = args[kern.ParamValue] == nil return } func isIntFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { result = kern.IsInteger(args[kern.ParamValue]) return } func isFloatFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { result = kern.IsFloat(args[kern.ParamValue]) return } func isBoolFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { result = kern.IsBool(args[kern.ParamValue]) return } func isStringFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { result = kern.IsString(args[kern.ParamValue]) return } func isFractionFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { result = kern.IsFraction(args[kern.ParamValue]) return } func isRationalFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { result = kern.IsRational(args[kern.ParamValue]) return } func isListFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { result = kern.IsList(args[kern.ParamValue]) return } func isDictionaryFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { result = kern.IsDict(args[kern.ParamValue]) return } func boolFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { switch v := args[kern.ParamValue].(type) { case int64: result = (v != 0) case *kern.FractionType: result = v.N() != 0 case float64: result = v != 0.0 case bool: result = v case string: result = len(v) > 0 case *kern.ListType: result = len(*v) > 0 case *kern.DictType: result = len(*v) > 0 default: err = kern.ErrCantConvert(name, v, "bool") } return } func intFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { switch v := args[kern.ParamValue].(type) { case int64: result = v case float64: result = int64(math.Trunc(v)) case bool: if v { result = int64(1) } else { result = int64(0) } case string: var i int if i, err = strconv.Atoi(v); err == nil { result = int64(i) } case *kern.FractionType: result = int64(v.N() / v.D()) default: err = kern.ErrCantConvert(name, v, "int") } return } func decFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { switch v := args[kern.ParamValue].(type) { case int64: result = float64(v) case float64: result = v case bool: if v { result = float64(1) } else { result = float64(0) } case string: var f float64 if f, err = strconv.ParseFloat(v, 64); err == nil { result = f } case *kern.FractionType: result = v.ToFloat() default: err = kern.ErrCantConvert(name, v, "float") } return } func stringFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { switch v := args[kern.ParamValue].(type) { case int64: result = strconv.FormatInt(v, 10) case float64: result = strconv.FormatFloat(v, 'g', -1, 64) case bool: if v { result = "true" } else { result = "false" } case string: result = v case *kern.FractionType: result = v.ToString(0) case kern.Formatter: result = v.ToString(0) case fmt.Stringer: result = v.String() default: err = kern.ErrCantConvert(name, v, "string") } return } func fractFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { switch v := args[kern.ParamValue].(type) { case int64: var den int64 = 1 var ok bool if den, ok = args[ParamDenominator].(int64); !ok { err = kern.ErrExpectedGot(name, "integer", args[ParamDenominator]) } else if den == 0 { err = kern.ErrFuncDivisionByZero(name) } if err == nil { result = kern.NewFraction(v, den) } case float64: result, err = kern.Float64ToFraction(v) case bool: if v { result = kern.NewFraction(1, 1) } else { result = kern.NewFraction(0, 1) } case string: result, err = kern.MakeGeneratingFraction(v) case *kern.FractionType: result = v default: err = kern.ErrCantConvert(name, v, "float") } return } // func iteratorFunc(ctx expr.ExprContext, name string, args []any) (result any, err error) { // return // } func evalFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { if source, ok := args[kern.ParamSource].(string); ok { var ast Expr parser := NewParser() if ctx == nil { ctx = NewSimpleStoreWithoutGlobalContext() } r := strings.NewReader(source) scanner := NewScanner(r, DefaultTranslations()) if ast, err = parser.Parse(scanner); err == nil { CtrlEnable(ctx, kern.ControlExportAll) result, err = ast.Eval(ctx) } } else { err = kern.ErrWrongParamType(name, kern.ParamSource, kern.TypeString, args[kern.ParamSource]) } return } func varFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var varName string var ok bool if varName, ok = args[kern.ParamName].(string); !ok { return nil, kern.ErrWrongParamType(name, kern.ParamName, kern.TypeString, args[kern.ParamName]) } if result, ok = args[kern.ParamValue]; ok && result != nil { ctx.GetParent().UnsafeSetVar(varName, result) // } else { // err = expr.ErrWrongParamType(name, expr.ParamSource, expr.TypeString, args[expr.ParamSource]) // } } else if result, ok = ctx.GetVar(varName); !ok { err = kern.ErrUnknownVar(name, varName) } return } func setFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var varName string var ok bool if varName, ok = args[kern.ParamName].(string); !ok { return nil, kern.ErrWrongParamType(name, kern.ParamName, kern.TypeString, args[kern.ParamName]) } if result, ok = args[kern.ParamValue]; ok { ctx.GetParent().UnsafeSetVar(varName, result) } else { err = kern.ErrWrongParamType(name, kern.ParamValue, kern.TypeAny, args[kern.ParamValue]) } return } func unsetFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var varName string var ok bool if varName, ok = args[kern.ParamName].(string); !ok { return nil, kern.ErrWrongParamType(name, kern.ParamName, kern.TypeString, args[kern.ParamName]) } else { ctx.GetParent().DeleteVar(varName) result = nil } return } //// import func ImportBuiltinsFuncs(ctx kern.ExprContext) { anyParams := []kern.ExprFuncParam{ NewFuncParam(kern.ParamValue), } ctx.RegisterFunc("isNil", kern.NewGolangFunctor(isNilFunc), kern.TypeBoolean, anyParams) ctx.RegisterFunc("isInt", kern.NewGolangFunctor(isIntFunc), kern.TypeBoolean, anyParams) ctx.RegisterFunc("isFloat", kern.NewGolangFunctor(isFloatFunc), kern.TypeBoolean, anyParams) ctx.RegisterFunc("isBool", kern.NewGolangFunctor(isBoolFunc), kern.TypeBoolean, anyParams) ctx.RegisterFunc("isString", kern.NewGolangFunctor(isStringFunc), kern.TypeBoolean, anyParams) ctx.RegisterFunc("isFract", kern.NewGolangFunctor(isFractionFunc), kern.TypeBoolean, anyParams) ctx.RegisterFunc("isRational", kern.NewGolangFunctor(isRationalFunc), kern.TypeBoolean, anyParams) ctx.RegisterFunc("isList", kern.NewGolangFunctor(isListFunc), kern.TypeBoolean, anyParams) ctx.RegisterFunc("isDict", kern.NewGolangFunctor(isDictionaryFunc), kern.TypeBoolean, anyParams) ctx.RegisterFunc("bool", kern.NewGolangFunctor(boolFunc), kern.TypeBoolean, anyParams) ctx.RegisterFunc("int", kern.NewGolangFunctor(intFunc), kern.TypeInt, anyParams) ctx.RegisterFunc("dec", kern.NewGolangFunctor(decFunc), kern.TypeFloat, anyParams) ctx.RegisterFunc("string", kern.NewGolangFunctor(stringFunc), kern.TypeString, anyParams) ctx.RegisterFunc("fract", kern.NewGolangFunctor(fractFunc), kern.TypeFraction, []kern.ExprFuncParam{ NewFuncParam(kern.ParamValue), NewFuncParamFlagDef(ParamDenominator, PfDefault, int64(1)), }) ctx.RegisterFunc("eval", kern.NewGolangFunctor(evalFunc), kern.TypeAny, []kern.ExprFuncParam{ NewFuncParam(kern.ParamSource), }) ctx.RegisterFunc("var", kern.NewGolangFunctor(varFunc), kern.TypeAny, []kern.ExprFuncParam{ NewFuncParam(kern.ParamName), NewFuncParamFlagDef(kern.ParamValue, PfDefault, nil), }) ctx.RegisterFunc("set", kern.NewGolangFunctor(setFunc), kern.TypeAny, []kern.ExprFuncParam{ NewFuncParam(kern.ParamName), NewFuncParam(kern.ParamValue), }) ctx.RegisterFunc("unset", kern.NewGolangFunctor(unsetFunc), kern.TypeAny, []kern.ExprFuncParam{ NewFuncParam(kern.ParamName), NewFuncParam(kern.ParamValue), }) } func init() { RegisterBuiltinModule("base", ImportBuiltinsFuncs, "Base expression tools like isNil(), int(), etc.") }