248 lines
6.2 KiB
Go
248 lines
6.2 KiB
Go
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
|
// All rights reserved.
|
|
|
|
// builtin-base.go
|
|
package expr
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
ParamDenominator = "denominator"
|
|
)
|
|
|
|
func isNilFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
|
|
result = args[ParamValue] == nil
|
|
return
|
|
}
|
|
|
|
func isIntFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
|
|
result = IsInteger(args[ParamValue])
|
|
return
|
|
}
|
|
|
|
func isFloatFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
|
|
result = IsFloat(args[ParamValue])
|
|
return
|
|
}
|
|
|
|
func isBoolFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
|
|
result = IsBool(args[ParamValue])
|
|
return
|
|
}
|
|
|
|
func isStringFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
|
|
result = IsString(args[ParamValue])
|
|
return
|
|
}
|
|
|
|
func isFractionFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
|
|
result = IsFract(args[ParamValue])
|
|
return
|
|
}
|
|
|
|
func isRationalFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
|
|
result = IsRational(args[ParamValue])
|
|
return
|
|
}
|
|
|
|
func isListFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
|
|
result = IsList(args[ParamValue])
|
|
return
|
|
}
|
|
|
|
func isDictionaryFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
|
|
result = IsDict(args[ParamValue])
|
|
return
|
|
}
|
|
|
|
func boolFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
|
|
switch v := args[ParamValue].(type) {
|
|
case int64:
|
|
result = (v != 0)
|
|
case *FractionType:
|
|
result = v.num != 0
|
|
case float64:
|
|
result = v != 0.0
|
|
case bool:
|
|
result = v
|
|
case string:
|
|
result = len(v) > 0
|
|
default:
|
|
err = ErrCantConvert(name, v, "bool")
|
|
}
|
|
return
|
|
}
|
|
|
|
func intFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
|
|
switch v := args[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)
|
|
}
|
|
default:
|
|
err = ErrCantConvert(name, v, "int")
|
|
}
|
|
return
|
|
}
|
|
|
|
func decFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
|
|
switch v := args[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 *FractionType:
|
|
result = v.toFloat()
|
|
default:
|
|
err = ErrCantConvert(name, v, "float")
|
|
}
|
|
return
|
|
}
|
|
|
|
func stringFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
|
|
switch v := args[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 *FractionType:
|
|
result = v.ToString(0)
|
|
case Formatter:
|
|
result = v.ToString(0)
|
|
case fmt.Stringer:
|
|
result = v.String()
|
|
default:
|
|
err = ErrCantConvert(name, v, "string")
|
|
}
|
|
return
|
|
}
|
|
|
|
func fractFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
|
|
switch v := args[ParamValue].(type) {
|
|
case int64:
|
|
var den int64 = 1
|
|
|
|
var ok bool
|
|
if den, ok = args[ParamDenominator].(int64); !ok {
|
|
err = ErrExpectedGot(name, "integer", args[ParamDenominator])
|
|
} else if den == 0 {
|
|
err = ErrFuncDivisionByZero(name)
|
|
}
|
|
|
|
if err == nil {
|
|
result = newFraction(v, den)
|
|
}
|
|
case float64:
|
|
result, err = float64ToFraction(v)
|
|
case bool:
|
|
if v {
|
|
result = newFraction(1, 1)
|
|
} else {
|
|
result = newFraction(0, 1)
|
|
}
|
|
case string:
|
|
result, err = makeGeneratingFraction(v)
|
|
case *FractionType:
|
|
result = v
|
|
default:
|
|
err = ErrCantConvert(name, v, "float")
|
|
}
|
|
return
|
|
}
|
|
|
|
// func iteratorFunc(ctx ExprContext, name string, args []any) (result any, err error) {
|
|
// return
|
|
// }
|
|
|
|
func evalFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) {
|
|
if source, ok := args[ParamSource].(string); ok {
|
|
var expr Expr
|
|
|
|
parser := NewParser()
|
|
if ctx == nil {
|
|
ctx = NewSimpleStore()
|
|
}
|
|
|
|
r := strings.NewReader(source)
|
|
scanner := NewScanner(r, DefaultTranslations())
|
|
|
|
if expr, err = parser.Parse(scanner); err == nil {
|
|
CtrlEnable(ctx, control_export_all)
|
|
result, err = expr.Eval(ctx)
|
|
}
|
|
} else {
|
|
err = ErrWrongParamType(name, ParamSource, TypeString, args[ParamSource])
|
|
}
|
|
return
|
|
}
|
|
|
|
//// import
|
|
|
|
func ImportBuiltinsFuncs(ctx ExprContext) {
|
|
anyParams := []ExprFuncParam{
|
|
NewFuncParam(ParamValue),
|
|
}
|
|
|
|
ctx.RegisterFunc("isNil", NewGolangFunctor(isNilFunc), TypeBoolean, anyParams)
|
|
ctx.RegisterFunc("isInt", NewGolangFunctor(isIntFunc), TypeBoolean, anyParams)
|
|
ctx.RegisterFunc("isFloat", NewGolangFunctor(isFloatFunc), TypeBoolean, anyParams)
|
|
ctx.RegisterFunc("isBool", NewGolangFunctor(isBoolFunc), TypeBoolean, anyParams)
|
|
ctx.RegisterFunc("isString", NewGolangFunctor(isStringFunc), TypeBoolean, anyParams)
|
|
ctx.RegisterFunc("isFract", NewGolangFunctor(isFractionFunc), TypeBoolean, anyParams)
|
|
ctx.RegisterFunc("isRational", NewGolangFunctor(isRationalFunc), TypeBoolean, anyParams)
|
|
ctx.RegisterFunc("isList", NewGolangFunctor(isListFunc), TypeBoolean, anyParams)
|
|
ctx.RegisterFunc("isDict", NewGolangFunctor(isDictionaryFunc), TypeBoolean, anyParams)
|
|
|
|
ctx.RegisterFunc("bool", NewGolangFunctor(boolFunc), TypeBoolean, anyParams)
|
|
ctx.RegisterFunc("int", NewGolangFunctor(intFunc), TypeInt, anyParams)
|
|
ctx.RegisterFunc("dec", NewGolangFunctor(decFunc), TypeFloat, anyParams)
|
|
ctx.RegisterFunc("string", NewGolangFunctor(stringFunc), TypeString, anyParams)
|
|
ctx.RegisterFunc("fract", NewGolangFunctor(fractFunc), TypeFraction, []ExprFuncParam{
|
|
NewFuncParam(ParamValue),
|
|
NewFuncParamFlagDef(ParamDenominator, PfDefault, int64(1)),
|
|
})
|
|
|
|
ctx.RegisterFunc("eval", NewGolangFunctor(evalFunc), TypeAny, []ExprFuncParam{
|
|
NewFuncParam(ParamSource),
|
|
})
|
|
}
|
|
|
|
func init() {
|
|
RegisterBuiltinModule("base", ImportBuiltinsFuncs, "Base expression tools like isNil(), int(), etc.")
|
|
}
|