319 lines
8.8 KiB
Go
319 lines
8.8 KiB
Go
// 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.IsFract(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.")
|
|
}
|