diff --git a/ast.go b/ast.go index 1f3e16d..f22ed9e 100644 --- a/ast.go +++ b/ast.go @@ -6,6 +6,8 @@ package expr import ( "strings" + + "git.portale-stac.it/go-pkg/expr/kern" ) //-------- ast @@ -19,33 +21,33 @@ func NewAst() *ast { return &ast{} } -func (expr *ast) TypeName() string { +func (ast *ast) TypeName() string { return "Expression" } -func (expr *ast) ToForest() { - if expr.root != nil { - if expr.forest == nil { - expr.forest = make([]*term, 0) +func (ast *ast) ToForest() { + if ast.root != nil { + if ast.forest == nil { + ast.forest = make([]*term, 0) } - expr.forest = append(expr.forest, expr.root) - expr.root = nil + ast.forest = append(ast.forest, ast.root) + ast.root = nil } } -func (expr *ast) String() string { +func (ast *ast) String() string { var sb strings.Builder - if expr.root == nil { + if ast.root == nil { sb.WriteString("(nil)") } else { - expr.root.toString(&sb) + ast.root.toString(&sb) } return sb.String() } -func (expr *ast) addTokens(tokens ...*Token) (err error) { +func (ast *ast) addTokens(tokens ...*Token) (err error) { for _, tk := range tokens { - if _, err = expr.addToken(tk); err != nil { + if _, err = ast.addToken(tk); err != nil { break } } @@ -57,31 +59,31 @@ func (expr *ast) addTokens(tokens ...*Token) (err error) { // return // } -func (expr *ast) addToken(tk *Token) (t *term, err error) { +func (ast *ast) addToken(tk *Token) (t *term, err error) { if t = newTerm(tk); t != nil { - err = expr.addTerm(t) + err = ast.addTerm(t) } else { err = tk.Errorf("unexpected token %q", tk.String()) } return } -func (expr *ast) addTerm(node *term) (err error) { - if expr.root == nil { - expr.root = node +func (ast *ast) addTerm(node *term) (err error) { + if ast.root == nil { + ast.root = node } else { - expr.root, err = expr.insert(expr.root, node) + ast.root, err = ast.insert(ast.root, node) } return } -func (expr *ast) insert(tree, node *term) (root *term, err error) { +func (ast *ast) insert(tree, node *term) (root *term, err error) { if tree.getPriority() < node.getPriority() { root = tree if tree.isComplete() { var subRoot *term last := tree.removeLastChild() - if subRoot, err = expr.insert(last, node); err == nil { + if subRoot, err = ast.insert(last, node); err == nil { subRoot.setParent(tree) } } else { @@ -96,22 +98,22 @@ func (expr *ast) insert(tree, node *term) (root *term, err error) { return } -func (expr *ast) Finish() { - if expr.root == nil && expr.forest != nil && len(expr.forest) >= 1 { - expr.root = expr.forest[len(expr.forest)-1] - expr.forest = expr.forest[0 : len(expr.forest)-1] +func (ast *ast) Finish() { + if ast.root == nil && ast.forest != nil && len(ast.forest) >= 1 { + ast.root = ast.forest[len(ast.forest)-1] + ast.forest = ast.forest[0 : len(ast.forest)-1] } } -func (expr *ast) Eval(ctx ExprContext) (result any, err error) { - expr.Finish() +func (ast *ast) Eval(ctx kern.ExprContext) (result any, err error) { + ast.Finish() - if expr.root != nil { + if ast.root != nil { // initDefaultVars(ctx) - if expr.forest != nil { - for _, root := range expr.forest { - if result, err = root.compute(ctx); err == nil { - ctx.UnsafeSetVar(ControlLastResult, result) + if ast.forest != nil { + for _, root := range ast.forest { + if result, err = root.Compute(ctx); err == nil { + ctx.UnsafeSetVar(kern.ControlLastResult, result) } else { //err = fmt.Errorf("error in expression nr %d: %v", i+1, err) break @@ -119,8 +121,8 @@ func (expr *ast) Eval(ctx ExprContext) (result any, err error) { } } if err == nil { - if result, err = expr.root.compute(ctx); err == nil { - ctx.UnsafeSetVar(ControlLastResult, result) + if result, err = ast.root.Compute(ctx); err == nil { + ctx.UnsafeSetVar(kern.ControlLastResult, result) } } // } else { diff --git a/bind-expr-functions.go b/bind-expr-functions.go index 99a6dd0..b1e7c06 100644 --- a/bind-expr-functions.go +++ b/bind-expr-functions.go @@ -4,20 +4,24 @@ // function.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + // ---- Linking with Expr functions type exprFunctor struct { - baseFunctor - params []ExprFuncParam + kern.BaseFunctor + params []kern.ExprFuncParam expr Expr - defCtx ExprContext + defCtx kern.ExprContext } -func (functor *exprFunctor) GetParams() (params []ExprFuncParam) { +func (functor *exprFunctor) GetParams() (params []kern.ExprFuncParam) { return functor.params } -func newExprFunctor(e Expr, params []ExprFuncParam, ctx ExprContext) *exprFunctor { - var defCtx ExprContext +func newExprFunctor(e Expr, params []kern.ExprFuncParam, ctx kern.ExprContext) *exprFunctor { + var defCtx kern.ExprContext if ctx != nil { defCtx = ctx } @@ -28,17 +32,17 @@ func (functor *exprFunctor) TypeName() string { return "ExprFunctor" } -func (functor *exprFunctor) GetDefinitionContext() ExprContext { +func (functor *exprFunctor) GetDefinitionContext() kern.ExprContext { return functor.defCtx } -func (functor *exprFunctor) InvokeNamed(ctx ExprContext, name string, args map[string]any) (result any, err error) { +func (functor *exprFunctor) InvokeNamed(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var missing []string for _, p := range functor.params { if arg, exists := args[p.Name()]; exists { - if funcArg, ok := arg.(Functor); ok { + if funcArg, ok := arg.(kern.Functor); ok { paramSpecs := funcArg.GetParams() - ctx.RegisterFunc(p.Name(), funcArg, TypeAny, paramSpecs) + ctx.RegisterFunc(p.Name(), funcArg, kern.TypeAny, paramSpecs) } else { ctx.UnsafeSetVar(p.Name(), arg) } @@ -51,7 +55,7 @@ func (functor *exprFunctor) InvokeNamed(ctx ExprContext, name string, args map[s } } if missing != nil { - err = ErrMissingParams(name, missing) + err = kern.ErrMissingParams(name, missing) } else { result, err = functor.expr.Eval(ctx) } diff --git a/builtin-base.go b/builtin-base.go index 3077e0f..45b89ce 100644 --- a/builtin-base.go +++ b/builtin-base.go @@ -9,81 +9,83 @@ import ( "math" "strconv" "strings" + + "git.portale-stac.it/go-pkg/expr/kern" ) const ( ParamDenominator = "denominator" ) -func isNilFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { - result = args[ParamValue] == nil +func isNilFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { + result = args[kern.ParamValue] == nil return } -func isIntFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { - result = IsInteger(args[ParamValue]) +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 ExprContext, name string, args map[string]any) (result any, err error) { - result = IsFloat(args[ParamValue]) +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 ExprContext, name string, args map[string]any) (result any, err error) { - result = IsBool(args[ParamValue]) +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 ExprContext, name string, args map[string]any) (result any, err error) { - result = IsString(args[ParamValue]) +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 ExprContext, name string, args map[string]any) (result any, err error) { - result = IsFract(args[ParamValue]) +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 ExprContext, name string, args map[string]any) (result any, err error) { - result = IsRational(args[ParamValue]) +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 ExprContext, name string, args map[string]any) (result any, err error) { - result = IsList(args[ParamValue]) +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 ExprContext, name string, args map[string]any) (result any, err error) { - result = IsDict(args[ParamValue]) +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 ExprContext, name string, args map[string]any) (result any, err error) { - switch v := args[ParamValue].(type) { +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 *FractionType: - result = v.num != 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 *ListType: + case *kern.ListType: result = len(*v) > 0 - case *DictType: + case *kern.DictType: result = len(*v) > 0 default: - err = ErrCantConvert(name, v, "bool") + err = kern.ErrCantConvert(name, v, "bool") } return } -func intFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { - switch v := args[ParamValue].(type) { +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: @@ -99,16 +101,16 @@ func intFunc(ctx ExprContext, name string, args map[string]any) (result any, err if i, err = strconv.Atoi(v); err == nil { result = int64(i) } - case *FractionType: - result = int64(v.num / v.den) + case *kern.FractionType: + result = int64(v.N() / v.D()) default: - err = ErrCantConvert(name, v, "int") + err = kern.ErrCantConvert(name, v, "int") } return } -func decFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { - switch v := args[ParamValue].(type) { +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: @@ -124,16 +126,16 @@ func decFunc(ctx ExprContext, name string, args map[string]any) (result any, err if f, err = strconv.ParseFloat(v, 64); err == nil { result = f } - case *FractionType: - result = v.toFloat() + case *kern.FractionType: + result = v.ToFloat() default: - err = ErrCantConvert(name, v, "float") + err = kern.ErrCantConvert(name, v, "float") } return } -func stringFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { - switch v := args[ParamValue].(type) { +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: @@ -146,118 +148,118 @@ func stringFunc(ctx ExprContext, name string, args map[string]any) (result any, } case string: result = v - case *FractionType: + case *kern.FractionType: result = v.ToString(0) - case Formatter: + case kern.Formatter: result = v.ToString(0) case fmt.Stringer: result = v.String() default: - err = ErrCantConvert(name, v, "string") + err = kern.ErrCantConvert(name, v, "string") } return } -func fractFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { - switch v := args[ParamValue].(type) { +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 = ErrExpectedGot(name, "integer", args[ParamDenominator]) + err = kern.ErrExpectedGot(name, "integer", args[ParamDenominator]) } else if den == 0 { - err = ErrFuncDivisionByZero(name) + err = kern.ErrFuncDivisionByZero(name) } if err == nil { - result = newFraction(v, den) + result = kern.NewFraction(v, den) } case float64: - result, err = float64ToFraction(v) + result, err = kern.Float64ToFraction(v) case bool: if v { - result = newFraction(1, 1) + result = kern.NewFraction(1, 1) } else { - result = newFraction(0, 1) + result = kern.NewFraction(0, 1) } case string: - result, err = makeGeneratingFraction(v) - case *FractionType: + result, err = kern.MakeGeneratingFraction(v) + case *kern.FractionType: result = v default: - err = ErrCantConvert(name, v, "float") + err = kern.ErrCantConvert(name, v, "float") } return } -// func iteratorFunc(ctx ExprContext, name string, args []any) (result any, err error) { +// func iteratorFunc(ctx expr.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 +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 = NewSimpleStore() + ctx = NewSimpleStoreWithoutGlobalContext() } 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) + if ast, err = parser.Parse(scanner); err == nil { + CtrlEnable(ctx, kern.ControlExportAll) + result, err = ast.Eval(ctx) } } else { - err = ErrWrongParamType(name, ParamSource, TypeString, args[ParamSource]) + err = kern.ErrWrongParamType(name, kern.ParamSource, kern.TypeString, args[kern.ParamSource]) } return } -func varFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { +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[ParamName].(string); !ok { - return nil, ErrWrongParamType(name, ParamName, TypeString, args[ParamName]) + if varName, ok = args[kern.ParamName].(string); !ok { + return nil, kern.ErrWrongParamType(name, kern.ParamName, kern.TypeString, args[kern.ParamName]) } - if result, ok = args[ParamValue]; ok && result != nil { + if result, ok = args[kern.ParamValue]; ok && result != nil { ctx.GetParent().UnsafeSetVar(varName, result) // } else { - // err = ErrWrongParamType(name, ParamSource, TypeString, args[ParamSource]) + // err = expr.ErrWrongParamType(name, expr.ParamSource, expr.TypeString, args[expr.ParamSource]) // } } else if result, ok = ctx.GetVar(varName); !ok { - err = ErrUnknownVar(name, varName) + err = kern.ErrUnknownVar(name, varName) } return } -func setFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { +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[ParamName].(string); !ok { - return nil, ErrWrongParamType(name, ParamName, TypeString, args[ParamName]) + if varName, ok = args[kern.ParamName].(string); !ok { + return nil, kern.ErrWrongParamType(name, kern.ParamName, kern.TypeString, args[kern.ParamName]) } - if result, ok = args[ParamValue]; ok { + if result, ok = args[kern.ParamValue]; ok { ctx.GetParent().UnsafeSetVar(varName, result) } else { - err = ErrWrongParamType(name, ParamValue, TypeAny, args[ParamValue]) + err = kern.ErrWrongParamType(name, kern.ParamValue, kern.TypeAny, args[kern.ParamValue]) } return } -func unsetFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { +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[ParamName].(string); !ok { - return nil, ErrWrongParamType(name, ParamName, TypeString, args[ParamName]) + 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 @@ -267,47 +269,47 @@ func unsetFunc(ctx ExprContext, name string, args map[string]any) (result any, e //// import -func ImportBuiltinsFuncs(ctx ExprContext) { - anyParams := []ExprFuncParam{ - NewFuncParam(ParamValue), +func ImportBuiltinsFuncs(ctx kern.ExprContext) { + anyParams := []kern.ExprFuncParam{ + NewFuncParam(kern.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("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", 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), + 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", NewGolangFunctor(evalFunc), TypeAny, []ExprFuncParam{ - NewFuncParam(ParamSource), + ctx.RegisterFunc("eval", kern.NewGolangFunctor(evalFunc), kern.TypeAny, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamSource), }) - ctx.RegisterFunc("var", NewGolangFunctor(varFunc), TypeAny, []ExprFuncParam{ - NewFuncParam(ParamName), - NewFuncParamFlagDef(ParamValue, PfDefault, nil), + ctx.RegisterFunc("var", kern.NewGolangFunctor(varFunc), kern.TypeAny, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamName), + NewFuncParamFlagDef(kern.ParamValue, PfDefault, nil), }) - ctx.RegisterFunc("set", NewGolangFunctor(setFunc), TypeAny, []ExprFuncParam{ - NewFuncParam(ParamName), - NewFuncParam(ParamValue), + ctx.RegisterFunc("set", kern.NewGolangFunctor(setFunc), kern.TypeAny, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamName), + NewFuncParam(kern.ParamValue), }) - ctx.RegisterFunc("unset", NewGolangFunctor(unsetFunc), TypeAny, []ExprFuncParam{ - NewFuncParam(ParamName), - NewFuncParam(ParamValue), + ctx.RegisterFunc("unset", kern.NewGolangFunctor(unsetFunc), kern.TypeAny, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamName), + NewFuncParam(kern.ParamValue), }) } diff --git a/builtin-fmt.go b/builtin-fmt.go index c721d33..9673674 100644 --- a/builtin-fmt.go +++ b/builtin-fmt.go @@ -8,11 +8,13 @@ import ( "fmt" "io" "os" + + "git.portale-stac.it/go-pkg/expr/kern" ) -func getStdout(ctx ExprContext) io.Writer { +func getStdout(ctx kern.ExprContext) io.Writer { var w io.Writer - if wany, exists := ctx.GetVar(ControlStdout); exists && wany != nil { + if wany, exists := ctx.GetVar(kern.ControlStdout); exists && wany != nil { w, _ = wany.(io.Writer) } if w == nil { @@ -21,9 +23,9 @@ func getStdout(ctx ExprContext) io.Writer { return w } -func printFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { +func printFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var n int = 0 - if v, exists := args[ParamItem]; exists && v != nil { + if v, exists := args[kern.ParamItem]; exists && v != nil { argv := v.([]any) n, err = fmt.Fprint(getStdout(ctx), argv...) } @@ -31,9 +33,9 @@ func printFunc(ctx ExprContext, name string, args map[string]any) (result any, e return } -func printLnFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { +func printLnFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var n int = 0 - if v, exists := args[ParamItem]; exists && v != nil { + if v, exists := args[kern.ParamItem]; exists && v != nil { argv := v.([]any) n, err = fmt.Fprintln(getStdout(ctx), argv...) } else { @@ -43,12 +45,12 @@ func printLnFunc(ctx ExprContext, name string, args map[string]any) (result any, return } -func ImportFmtFuncs(ctx ExprContext) { - ctx.RegisterFunc("print", NewGolangFunctor(printFunc), TypeInt, []ExprFuncParam{ - NewFuncParamFlag(ParamItem, PfRepeat), +func ImportFmtFuncs(ctx kern.ExprContext) { + ctx.RegisterFunc("print", kern.NewGolangFunctor(printFunc), kern.TypeInt, []kern.ExprFuncParam{ + NewFuncParamFlag(kern.ParamItem, PfRepeat), }) - ctx.RegisterFunc("println", NewGolangFunctor(printLnFunc), TypeInt, []ExprFuncParam{ - NewFuncParamFlag(ParamItem, PfRepeat), + ctx.RegisterFunc("println", kern.NewGolangFunctor(printLnFunc), kern.TypeInt, []kern.ExprFuncParam{ + NewFuncParamFlag(kern.ParamItem, PfRepeat), }) } diff --git a/builtin-import.go b/builtin-import.go index 065583b..2ba6554 100644 --- a/builtin-import.go +++ b/builtin-import.go @@ -7,27 +7,29 @@ package expr import ( "io" "os" + + "git.portale-stac.it/go-pkg/expr/kern" ) -func importFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { +func importFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { return importGeneral(ctx, name, args) } -func importAllFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { - CtrlEnable(ctx, control_export_all) +func importAllFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { + CtrlEnable(ctx, kern.ControlExportAll) return importGeneral(ctx, name, args) } -func importGeneral(ctx ExprContext, name string, args map[string]any) (result any, err error) { - dirList := buildSearchDirList("sources", ENV_EXPR_SOURCE_PATH) - if v, exists := args[ParamFilepath]; exists && v != nil { +func importGeneral(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { + dirList := buildSearchDirList(ctx, "sources", ENV_EXPR_SOURCE_PATH) + if v, exists := args[kern.ParamFilepath]; exists && v != nil { argv := v.([]any) result, err = doImport(ctx, name, dirList, NewArrayIterator(argv)) } return } -func doImport(ctx ExprContext, name string, dirList []string, it Iterator) (result any, err error) { +func doImport(ctx kern.ExprContext, name string, dirList []string, it kern.Iterator) (result any, err error) { var v any var sourceFilepath string @@ -64,12 +66,12 @@ func doImport(ctx ExprContext, name string, dirList []string, it Iterator) (resu return } -func ImportImportFuncs(ctx ExprContext) { - ctx.RegisterFunc("import", NewGolangFunctor(importFunc), TypeAny, []ExprFuncParam{ - NewFuncParamFlag(ParamFilepath, PfRepeat), +func ImportImportFuncs(ctx kern.ExprContext) { + ctx.RegisterFunc("import", kern.NewGolangFunctor(importFunc), kern.TypeAny, []kern.ExprFuncParam{ + NewFuncParamFlag(kern.ParamFilepath, PfRepeat), }) - ctx.RegisterFunc("importAll", NewGolangFunctor(importAllFunc), TypeAny, []ExprFuncParam{ - NewFuncParamFlag(ParamFilepath, PfRepeat), + ctx.RegisterFunc("importAll", kern.NewGolangFunctor(importAllFunc), kern.TypeAny, []kern.ExprFuncParam{ + NewFuncParamFlag(kern.ParamFilepath, PfRepeat), }) } diff --git a/builtin-iterator.go b/builtin-iterator.go index 91283cd..5bc4595 100644 --- a/builtin-iterator.go +++ b/builtin-iterator.go @@ -7,6 +7,8 @@ package expr import ( "fmt" "io" + + "git.portale-stac.it/go-pkg/expr/kern" ) const ( @@ -15,24 +17,24 @@ const ( iterVarStatus = "status" ) -func parseRunArgs(localCtx ExprContext, args map[string]any) (it Iterator, op Functor, err error) { +func parseRunArgs(localCtx kern.ExprContext, args map[string]any) (it kern.Iterator, op kern.Functor, err error) { var ok bool - if it, ok = args[ParamIterator].(Iterator); !ok { - err = fmt.Errorf("paramter %q must be an iterator, passed %v [%s]", ParamIterator, args[ParamIterator], TypeName(args[ParamIterator])) + if it, ok = args[kern.ParamIterator].(kern.Iterator); !ok { + err = fmt.Errorf("paramter %q must be an iterator, passed %v [%s]", kern.ParamIterator, args[kern.ParamIterator], kern.TypeName(args[kern.ParamIterator])) return } if args[iterParamOperator] != nil { - if op, ok = args[iterParamOperator].(Functor); !ok || op == nil { - err = fmt.Errorf("paramter %q must be a function, passed %v [%s]", iterParamOperator, args[iterParamOperator], TypeName(args[iterParamOperator])) + if op, ok = args[iterParamOperator].(kern.Functor); !ok || op == nil { + err = fmt.Errorf("paramter %q must be a function, passed %v [%s]", iterParamOperator, args[iterParamOperator], kern.TypeName(args[iterParamOperator])) return } } - var vars *DictType - if vars, ok = args[iterParamVars].(*DictType); !ok && args[iterParamVars] != nil { - err = fmt.Errorf("paramter %q must be a dictionary, passed %v [%s]", iterParamVars, args[iterParamVars], TypeName(args[iterParamVars])) + var vars *kern.DictType + if vars, ok = args[iterParamVars].(*kern.DictType); !ok && args[iterParamVars] != nil { + err = fmt.Errorf("paramter %q must be a dictionary, passed %v [%s]", iterParamVars, args[iterParamVars], kern.TypeName(args[iterParamVars])) return } @@ -48,10 +50,10 @@ func parseRunArgs(localCtx ExprContext, args map[string]any) (it Iterator, op Fu return } -func runFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { - var it Iterator +func runFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { + var it kern.Iterator var ok bool - var op Functor + var op kern.Functor var v any // var usingDefaultOp = false var params map[string]any @@ -62,25 +64,16 @@ func runFunc(ctx ExprContext, name string, args map[string]any) (result any, err if it, op, err = parseRunArgs(localCtx, args); err != nil { return - // } else if op == nil { - // op = NewGolangFunctor(printLnFunc) - // usingDefaultOp = true } for item, err = it.Next(); err == nil; item, err = it.Next() { - // if usingDefaultOp { - // params = map[string]any{ParamItem: []any{item}} - // } else { - // params = map[string]any{ParamIndex: it.Index(), ParamItem: item} - // } - if op != nil { - params = map[string]any{ParamIndex: it.Index(), ParamItem: item} + params = map[string]any{kern.ParamIndex: it.Index(), kern.ParamItem: item} if v, err = op.InvokeNamed(localCtx, iterParamOperator, params); err != nil { break } else { var success bool - if success, ok = ToBool(v); !success || !ok { + if success, ok = kern.ToBool(v); !success || !ok { break } } @@ -99,9 +92,9 @@ func runFunc(ctx ExprContext, name string, args map[string]any) (result any, err return } -func ImportIterFuncs(ctx ExprContext) { - ctx.RegisterFunc("run", NewGolangFunctor(runFunc), TypeAny, []ExprFuncParam{ - NewFuncParam(ParamIterator), +func ImportIterFuncs(ctx kern.ExprContext) { + ctx.RegisterFunc("run", kern.NewGolangFunctor(runFunc), kern.TypeAny, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamIterator), NewFuncParamFlag(iterParamOperator, PfOptional), NewFuncParamFlag(iterParamVars, PfOptional), }) diff --git a/builtin-math-arith.go b/builtin-math-arith.go index 7be529c..75ca18c 100644 --- a/builtin-math-arith.go +++ b/builtin-math-arith.go @@ -7,35 +7,37 @@ package expr import ( "fmt" "io" + + "git.portale-stac.it/go-pkg/expr/kern" ) func checkNumberParamExpected(funcName string, paramValue any, paramPos, level, subPos int) (err error) { - if !(IsNumber(paramValue) || isFraction(paramValue)) /*|| isList(paramValue)*/ { + if !(kern.IsNumber(paramValue) || kern.IsFraction(paramValue)) /*|| isList(paramValue)*/ { err = fmt.Errorf("%s(): param nr %d (%d in %d) has wrong type %T, number expected", funcName, paramPos+1, subPos+1, level, paramValue) } return } -func doAdd(ctx ExprContext, name string, it Iterator, count, level int) (result any, err error) { +func doAdd(ctx kern.ExprContext, name string, it kern.Iterator, count, level int) (result any, err error) { var sumAsFloat, sumAsFract bool var floatSum float64 = 0.0 var intSum int64 = 0 - var fractSum *FractionType + var fractSum *kern.FractionType var v any level++ for v, err = it.Next(); err == nil; v, err = it.Next() { - if list, ok := v.(*ListType); ok { + if list, ok := v.(*kern.ListType); ok { v = NewListIterator(list, nil) } - if subIter, ok := v.(Iterator); ok { + if subIter, ok := v.(kern.Iterator); ok { if v, err = doAdd(ctx, name, subIter, count, level); err != nil { break } - if extIter, ok := v.(ExtIterator); ok && extIter.HasOperation(CleanName) { - if _, err = extIter.CallOperation(CleanName, nil); err != nil { + if extIter, ok := v.(kern.ExtIterator); ok && extIter.HasOperation(kern.CleanName) { + if _, err = extIter.CallOperation(kern.CleanName, nil); err != nil { return } } @@ -45,29 +47,29 @@ func doAdd(ctx ExprContext, name string, it Iterator, count, level int) (result count++ if !sumAsFloat { - if IsFloat(v) { + if kern.IsFloat(v) { sumAsFloat = true if sumAsFract { - floatSum = fractSum.toFloat() + floatSum = fractSum.ToFloat() } else { floatSum = float64(intSum) } - } else if !sumAsFract && isFraction(v) { - fractSum = newFraction(intSum, 1) + } else if !sumAsFract && kern.IsFraction(v) { + fractSum = kern.NewFraction(intSum, 1) sumAsFract = true } } if sumAsFloat { - floatSum += numAsFloat(v) + floatSum += kern.NumAsFloat(v) } else if sumAsFract { - var item *FractionType + var item *kern.FractionType var ok bool - if item, ok = v.(*FractionType); !ok { + if item, ok = v.(*kern.FractionType); !ok { iv, _ := v.(int64) - item = newFraction(iv, 1) + item = kern.NewFraction(iv, 1) } - fractSum = sumFract(fractSum, item) + fractSum = kern.SumFract(fractSum, item) } else { iv, _ := v.(int64) intSum += iv @@ -86,30 +88,30 @@ func doAdd(ctx ExprContext, name string, it Iterator, count, level int) (result return } -func addFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { - argv := args[ParamValue].([]any) +func addFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { + argv := args[kern.ParamValue].([]any) result, err = doAdd(ctx, name, NewArrayIterator(argv), 0, -1) return } -func doMul(ctx ExprContext, name string, it Iterator, count, level int) (result any, err error) { +func doMul(ctx kern.ExprContext, name string, it kern.Iterator, count, level int) (result any, err error) { var mulAsFloat, mulAsFract bool var floatProd float64 = 1.0 var intProd int64 = 1 - var fractProd *FractionType + var fractProd *kern.FractionType var v any level++ for v, err = it.Next(); err == nil; v, err = it.Next() { - if list, ok := v.(*ListType); ok { + if list, ok := v.(*kern.ListType); ok { v = NewListIterator(list, nil) } - if subIter, ok := v.(Iterator); ok { + if subIter, ok := v.(kern.Iterator); ok { if v, err = doMul(ctx, name, subIter, count, level); err != nil { break } - if extIter, ok := v.(ExtIterator); ok && extIter.HasOperation(CleanName) { - if _, err = extIter.CallOperation(CleanName, nil); err != nil { + if extIter, ok := v.(kern.ExtIterator); ok && extIter.HasOperation(kern.CleanName) { + if _, err = extIter.CallOperation(kern.CleanName, nil); err != nil { return } } @@ -121,29 +123,29 @@ func doMul(ctx ExprContext, name string, it Iterator, count, level int) (result count++ if !mulAsFloat { - if IsFloat(v) { + if kern.IsFloat(v) { mulAsFloat = true if mulAsFract { - floatProd = fractProd.toFloat() + floatProd = fractProd.ToFloat() } else { floatProd = float64(intProd) } - } else if !mulAsFract && isFraction(v) { - fractProd = newFraction(intProd, 1) + } else if !mulAsFract && kern.IsFraction(v) { + fractProd = kern.NewFraction(intProd, 1) mulAsFract = true } } if mulAsFloat { - floatProd *= numAsFloat(v) + floatProd *= kern.NumAsFloat(v) } else if mulAsFract { - var item *FractionType + var item *kern.FractionType var ok bool - if item, ok = v.(*FractionType); !ok { + if item, ok = v.(*kern.FractionType); !ok { iv, _ := v.(int64) - item = newFraction(iv, 1) + item = kern.NewFraction(iv, 1) } - fractProd = mulFract(fractProd, item) + fractProd = kern.MulFract(fractProd, item) } else { iv, _ := v.(int64) intProd *= iv @@ -162,19 +164,19 @@ func doMul(ctx ExprContext, name string, it Iterator, count, level int) (result return } -func mulFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { - argv := args[ParamValue].([]any) +func mulFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { + argv := args[kern.ParamValue].([]any) result, err = doMul(ctx, name, NewArrayIterator(argv), 0, -1) return } -func ImportMathFuncs(ctx ExprContext) { - ctx.RegisterFunc("add", NewGolangFunctor(addFunc), TypeNumber, []ExprFuncParam{ - NewFuncParamFlagDef(ParamValue, PfDefault|PfRepeat, int64(0)), +func ImportMathFuncs(ctx kern.ExprContext) { + ctx.RegisterFunc("add", kern.NewGolangFunctor(addFunc), kern.TypeNumber, []kern.ExprFuncParam{ + NewFuncParamFlagDef(kern.ParamValue, PfDefault|PfRepeat, int64(0)), }) - ctx.RegisterFunc("mul", NewGolangFunctor(mulFunc), TypeNumber, []ExprFuncParam{ - NewFuncParamFlagDef(ParamValue, PfDefault|PfRepeat, int64(1)), + ctx.RegisterFunc("mul", kern.NewGolangFunctor(mulFunc), kern.TypeNumber, []kern.ExprFuncParam{ + NewFuncParamFlagDef(kern.ParamValue, PfDefault|PfRepeat, int64(1)), }) } diff --git a/builtin-os-file-iter.go b/builtin-os-file-iter.go index ef736b1..9b415e3 100644 --- a/builtin-os-file-iter.go +++ b/builtin-os-file-iter.go @@ -8,6 +8,8 @@ import ( "fmt" "io" "slices" + + "git.portale-stac.it/go-pkg/expr/kern" ) const paramHandleOrPath = "handle-or-path" @@ -74,7 +76,7 @@ func (it *fileReadTextIterator) Reset() (err error) { } func (it *fileReadTextIterator) HasOperation(name string) bool { - return slices.Contains([]string{NextName, ResetName, IndexName, CountName, CurrentName, CleanName}, name) + return slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName, kern.CleanName}, name) } func (it *fileReadTextIterator) Clean() (err error) { @@ -88,25 +90,25 @@ func (it *fileReadTextIterator) Clean() (err error) { func (it *fileReadTextIterator) CallOperation(name string, args map[string]any) (v any, err error) { switch name { - case NextName: + case kern.NextName: v, err = it.Next() - case ResetName: + case kern.ResetName: err = it.Reset() - case CleanName: + case kern.CleanName: err = it.Clean() - case IndexName: + case kern.IndexName: v = int64(it.Index()) - case CurrentName: + case kern.CurrentName: v, err = it.Current() - case CountName: + case kern.CountName: v = it.count default: - err = errNoOperation(name) + err = kern.ErrNoOperation(name) } return } -func fileReadIteratorFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { +func fileReadIteratorFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var handle *osReader var invalidFileHandle any var ok, autoClose bool @@ -115,7 +117,7 @@ func fileReadIteratorFunc(ctx ExprContext, name string, args map[string]any) (re if handle, ok = args[paramHandleOrPath].(*osReader); !ok { if fileName, ok := args[paramHandleOrPath].(string); ok && len(fileName) > 0 { var handleAny any - if handleAny, err = openFileFunc(ctx, name, map[string]any{ParamFilepath: fileName}); err != nil { + if handleAny, err = openFileFunc(ctx, name, map[string]any{kern.ParamFilepath: fileName}); err != nil { return } if handleAny != nil { diff --git a/builtin-os-file.go b/builtin-os-file.go index bb12f37..70b7ac3 100644 --- a/builtin-os-file.go +++ b/builtin-os-file.go @@ -9,6 +9,8 @@ import ( "fmt" "io" "os" + + "git.portale-stac.it/go-pkg/expr/kern" ) const ( @@ -65,8 +67,8 @@ func errInvalidFileHandle(funcName string, v any) error { } } -func createFileFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { - if filePath, ok := args[ParamFilepath].(string); ok && len(filePath) > 0 { +func createFileFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { + if filePath, ok := args[kern.ParamFilepath].(string); ok && len(filePath) > 0 { var fh *os.File if fh, err = os.Create(filePath); err == nil { result = &osWriter{fh: fh, writer: bufio.NewWriter(fh)} @@ -77,8 +79,8 @@ func createFileFunc(ctx ExprContext, name string, args map[string]any) (result a return } -func openFileFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { - if filePath, ok := args[ParamFilepath].(string); ok && len(filePath) > 0 { +func openFileFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { + if filePath, ok := args[kern.ParamFilepath].(string); ok && len(filePath) > 0 { var fh *os.File if fh, err = os.Open(filePath); err == nil { result = &osReader{fh: fh, reader: bufio.NewReader(fh)} @@ -89,8 +91,8 @@ func openFileFunc(ctx ExprContext, name string, args map[string]any) (result any return } -func appendFileFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { - if filePath, ok := args[ParamFilepath].(string); ok && len(filePath) > 0 { +func appendFileFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { + if filePath, ok := args[kern.ParamFilepath].(string); ok && len(filePath) > 0 { var fh *os.File if fh, err = os.OpenFile(filePath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0660); err == nil { result = &osWriter{fh: fh, writer: bufio.NewWriter(fh)} @@ -101,13 +103,13 @@ func appendFileFunc(ctx ExprContext, name string, args map[string]any) (result a return } -func closeFileFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { +func closeFileFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var handle osHandle var invalidFileHandle any var ok bool - if handle, ok = args[ParamHandle].(osHandle); !ok { - invalidFileHandle = args[ParamHandle] + if handle, ok = args[kern.ParamHandle].(osHandle); !ok { + invalidFileHandle = args[kern.ParamHandle] } if handle != nil { @@ -128,18 +130,18 @@ func closeFileFunc(ctx ExprContext, name string, args map[string]any) (result an return } -func fileWriteTextFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { +func fileWriteTextFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var handle osHandle var invalidFileHandle any var ok bool - if handle, ok = args[ParamHandle].(osHandle); !ok { - invalidFileHandle = args[ParamHandle] + if handle, ok = args[kern.ParamHandle].(osHandle); !ok { + invalidFileHandle = args[kern.ParamHandle] } if handle != nil { if w, ok := handle.(*osWriter); ok { - if v, exists := args[ParamItem]; exists { + if v, exists := args[kern.ParamItem]; exists { argv := v.([]any) result, err = fmt.Fprint(w.writer, argv...) } @@ -154,14 +156,14 @@ func fileWriteTextFunc(ctx ExprContext, name string, args map[string]any) (resul return } -func fileReadTextFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { +func fileReadTextFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var handle osHandle var invalidFileHandle any var ok bool result = nil - if handle, ok = args[ParamHandle].(osHandle); !ok || args[ParamHandle] == nil { - invalidFileHandle = args[ParamHandle] + if handle, ok = args[kern.ParamHandle].(osHandle); !ok || args[kern.ParamHandle] == nil { + invalidFileHandle = args[kern.ParamHandle] } if handle != nil { @@ -194,14 +196,14 @@ func fileReadTextFunc(ctx ExprContext, name string, args map[string]any) (result return } -func fileReadTextAllFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { +func fileReadTextAllFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var handle osHandle var invalidFileHandle any var ok bool result = nil - if handle, ok = args[ParamHandle].(osHandle); !ok || args[ParamHandle] == nil { - invalidFileHandle = args[ParamHandle] + if handle, ok = args[kern.ParamHandle].(osHandle); !ok || args[kern.ParamHandle] == nil { + invalidFileHandle = args[kern.ParamHandle] } if handle != nil { @@ -220,38 +222,38 @@ func fileReadTextAllFunc(ctx ExprContext, name string, args map[string]any) (res return } -func ImportOsFuncs(ctx ExprContext) { - ctx.RegisterFunc("fileOpen", NewGolangFunctor(openFileFunc), TypeFileHandle, []ExprFuncParam{ - NewFuncParam(ParamFilepath), +func ImportOsFuncs(ctx kern.ExprContext) { + ctx.RegisterFunc("fileOpen", kern.NewGolangFunctor(openFileFunc), kern.TypeFileHandle, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamFilepath), }) - ctx.RegisterFunc("fileAppend", NewGolangFunctor(appendFileFunc), TypeFileHandle, []ExprFuncParam{ - NewFuncParam(ParamFilepath), + ctx.RegisterFunc("fileAppend", kern.NewGolangFunctor(appendFileFunc), kern.TypeFileHandle, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamFilepath), }) - ctx.RegisterFunc("fileCreate", NewGolangFunctor(createFileFunc), TypeFileHandle, []ExprFuncParam{ - NewFuncParam(ParamFilepath), + ctx.RegisterFunc("fileCreate", kern.NewGolangFunctor(createFileFunc), kern.TypeFileHandle, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamFilepath), }) - ctx.RegisterFunc("fileClose", NewGolangFunctor(closeFileFunc), TypeBoolean, []ExprFuncParam{ - NewFuncParam(ParamHandle), + ctx.RegisterFunc("fileClose", kern.NewGolangFunctor(closeFileFunc), kern.TypeBoolean, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamHandle), }) - ctx.RegisterFunc("fileWriteText", NewGolangFunctor(fileWriteTextFunc), TypeInt, []ExprFuncParam{ - NewFuncParam(ParamHandle), - NewFuncParamFlagDef(ParamItem, PfDefault|PfRepeat, ""), + ctx.RegisterFunc("fileWriteText", kern.NewGolangFunctor(fileWriteTextFunc), kern.TypeInt, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamHandle), + NewFuncParamFlagDef(kern.ParamItem, PfDefault|PfRepeat, ""), }) - ctx.RegisterFunc("fileReadText", NewGolangFunctor(fileReadTextFunc), TypeString, []ExprFuncParam{ - NewFuncParam(ParamHandle), + ctx.RegisterFunc("fileReadText", kern.NewGolangFunctor(fileReadTextFunc), kern.TypeString, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamHandle), NewFuncParamFlagDef(osLimitCh, PfDefault, "\n"), }) - ctx.RegisterFunc("fileReadTextAll", NewGolangFunctor(fileReadTextAllFunc), TypeString, []ExprFuncParam{ - NewFuncParam(ParamHandle), + ctx.RegisterFunc("fileReadTextAll", kern.NewGolangFunctor(fileReadTextAllFunc), kern.TypeString, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamHandle), }) - ctx.RegisterFunc("fileReadIterator", NewGolangFunctor(fileReadIteratorFunc), TypeIterator, []ExprFuncParam{ + ctx.RegisterFunc("fileReadIterator", kern.NewGolangFunctor(fileReadIteratorFunc), kern.TypeIterator, []kern.ExprFuncParam{ NewFuncParam(paramHandleOrPath), }) } diff --git a/builtin-string.go b/builtin-string.go index 2d487ae..35d56ce 100644 --- a/builtin-string.go +++ b/builtin-string.go @@ -8,6 +8,8 @@ import ( "fmt" "io" "strings" + + "git.portale-stac.it/go-pkg/expr/kern" ) const ( @@ -15,7 +17,7 @@ const ( ) // --- Start of function definitions -func doJoinStr(funcName string, sep string, it Iterator) (result any, err error) { +func doJoinStr(funcName string, sep string, it kern.Iterator) (result any, err error) { var sb strings.Builder var v any for v, err = it.Next(); err == nil; v, err = it.Next() { @@ -25,7 +27,7 @@ func doJoinStr(funcName string, sep string, it Iterator) (result any, err error) if s, ok := v.(string); ok { sb.WriteString(s) } else { - err = ErrExpectedGot(funcName, TypeString, v) + err = kern.ErrExpectedGot(funcName, kern.TypeString, v) return } } @@ -36,45 +38,45 @@ func doJoinStr(funcName string, sep string, it Iterator) (result any, err error) return } -func joinStrFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { - if sep, ok := args[ParamSeparator].(string); ok { - if v, exists := args[ParamItem]; exists { +func joinStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { + if sep, ok := args[kern.ParamSeparator].(string); ok { + if v, exists := args[kern.ParamItem]; exists { argv := v.([]any) if len(argv) == 1 { - if ls, ok := argv[0].(*ListType); ok { + if ls, ok := argv[0].(*kern.ListType); ok { result, err = doJoinStr(name, sep, NewListIterator(ls, nil)) - } else if it, ok := argv[0].(Iterator); ok { + } else if it, ok := argv[0].(kern.Iterator); ok { result, err = doJoinStr(name, sep, it) } else if s, ok := argv[0].(string); ok { result = s } else { - err = ErrInvalidParameterValue(name, ParamItem, v) + err = kern.ErrInvalidParameterValue(name, kern.ParamItem, v) } } else { result, err = doJoinStr(name, sep, NewArrayIterator(argv)) } } } else { - err = ErrWrongParamType(name, ParamSeparator, TypeString, args[ParamSeparator]) + err = kern.ErrWrongParamType(name, kern.ParamSeparator, kern.TypeString, args[kern.ParamSeparator]) } return } -func subStrFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { +func subStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var start = 0 var count = -1 var source string var ok bool - if source, ok = args[ParamSource].(string); !ok { - return nil, ErrWrongParamType(name, ParamSource, TypeString, args[ParamSource]) + if source, ok = args[kern.ParamSource].(string); !ok { + return nil, kern.ErrWrongParamType(name, kern.ParamSource, kern.TypeString, args[kern.ParamSource]) } - if start, err = ToGoInt(args[ParamStart], name+"()"); err != nil { + if start, err = kern.ToGoInt(args[kern.ParamStart], name+"()"); err != nil { return } - if count, err = ToGoInt(args[ParamCount], name+"()"); err != nil { + if count, err = kern.ToGoInt(args[kern.ParamCount], name+"()"); err != nil { return } @@ -90,29 +92,29 @@ func subStrFunc(ctx ExprContext, name string, args map[string]any) (result any, return } -func trimStrFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { +func trimStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var source string var ok bool - if source, ok = args[ParamSource].(string); !ok { - return nil, ErrWrongParamType(name, ParamSource, TypeString, args[ParamSource]) + if source, ok = args[kern.ParamSource].(string); !ok { + return nil, kern.ErrWrongParamType(name, kern.ParamSource, kern.TypeString, args[kern.ParamSource]) } result = strings.TrimSpace(source) return } -func startsWithStrFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { +func startsWithStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var source, prefix string var ok bool result = false - if source, ok = args[ParamSource].(string); !ok { - return result, ErrWrongParamType(name, ParamSource, TypeString, args[ParamSource]) + if source, ok = args[kern.ParamSource].(string); !ok { + return result, kern.ErrWrongParamType(name, kern.ParamSource, kern.TypeString, args[kern.ParamSource]) } - if prefix, ok = args[ParamPrefix].(string); !ok { - return result, ErrWrongParamType(name, ParamPrefix, TypeString, args[ParamPrefix]) + if prefix, ok = args[kern.ParamPrefix].(string); !ok { + return result, kern.ErrWrongParamType(name, kern.ParamPrefix, kern.TypeString, args[kern.ParamPrefix]) } if strings.HasPrefix(source, prefix) { result = true @@ -125,7 +127,7 @@ func startsWithStrFunc(ctx ExprContext, name string, args map[string]any) (resul break } } else { - err = fmt.Errorf("target item nr %d is %s, string expected", i+1, TypeName(targetSpec)) + err = fmt.Errorf("target item nr %d is %s, string expected", i+1, kern.TypeName(targetSpec)) break } } @@ -133,18 +135,18 @@ func startsWithStrFunc(ctx ExprContext, name string, args map[string]any) (resul return } -func endsWithStrFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { +func endsWithStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var source, suffix string var ok bool result = false - if source, ok = args[ParamSource].(string); !ok { - return result, ErrWrongParamType(name, ParamSource, TypeString, args[ParamSource]) + if source, ok = args[kern.ParamSource].(string); !ok { + return result, kern.ErrWrongParamType(name, kern.ParamSource, kern.TypeString, args[kern.ParamSource]) } - if suffix, ok = args[ParamSuffix].(string); !ok { - return result, ErrWrongParamType(name, ParamSuffix, TypeString, args[ParamSuffix]) + if suffix, ok = args[kern.ParamSuffix].(string); !ok { + return result, kern.ErrWrongParamType(name, kern.ParamSuffix, kern.TypeString, args[kern.ParamSuffix]) } if strings.HasPrefix(source, suffix) { result = true @@ -157,7 +159,7 @@ func endsWithStrFunc(ctx ExprContext, name string, args map[string]any) (result break } } else { - err = fmt.Errorf("target item nr %d is %s, string expected", i+1, TypeName(targetSpec)) + err = fmt.Errorf("target item nr %d is %s, string expected", i+1, kern.TypeName(targetSpec)) break } } @@ -165,24 +167,24 @@ func endsWithStrFunc(ctx ExprContext, name string, args map[string]any) (result return } -func splitStrFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { +func splitStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var source, sep string var count int = -1 var parts []string var ok bool - if source, ok = args[ParamSource].(string); !ok { - return result, ErrWrongParamType(name, ParamSource, TypeString, args[ParamSource]) + if source, ok = args[kern.ParamSource].(string); !ok { + return result, kern.ErrWrongParamType(name, kern.ParamSource, kern.TypeString, args[kern.ParamSource]) } - if sep, ok = args[ParamSeparator].(string); !ok { - return nil, fmt.Errorf("separator param must be string, got %s (%v)", TypeName(args[ParamSeparator]), args[ParamSeparator]) + if sep, ok = args[kern.ParamSeparator].(string); !ok { + return nil, fmt.Errorf("separator param must be string, got %s (%v)", kern.TypeName(args[kern.ParamSeparator]), args[kern.ParamSeparator]) } - if count64, ok := args[ParamCount].(int64); ok { // TODO replace type assertion with toInt() + if count64, ok := args[kern.ParamCount].(int64); ok { // TODO replace type assertion with toInt() count = int(count64) } else { - return nil, fmt.Errorf("part count must be integer, got %s (%v)", TypeName(args[ParamCount]), args[ParamCount]) + return nil, fmt.Errorf("part count must be integer, got %s (%v)", kern.TypeName(args[kern.ParamCount]), args[kern.ParamCount]) } if count > 0 { @@ -192,7 +194,7 @@ func splitStrFunc(ctx ExprContext, name string, args map[string]any) (result any } else { parts = []string{} } - list := make(ListType, len(parts)) + list := make(kern.ListType, len(parts)) for i, part := range parts { list[i] = part } @@ -200,20 +202,20 @@ func splitStrFunc(ctx ExprContext, name string, args map[string]any) (result any return } -func upperStrFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { - if source, ok := args[ParamSource].(string); ok { +func upperStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { + if source, ok := args[kern.ParamSource].(string); ok { result = strings.ToUpper(source) } else { - err = ErrWrongParamType(name, ParamSource, TypeString, args[ParamSource]) + err = kern.ErrWrongParamType(name, kern.ParamSource, kern.TypeString, args[kern.ParamSource]) } return } -func lowerStrFunc(ctx ExprContext, name string, args map[string]any) (result any, err error) { - if source, ok := args[ParamSource].(string); ok { +func lowerStrFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { + if source, ok := args[kern.ParamSource].(string); ok { result = strings.ToLower(source) } else { - err = ErrWrongParamType(name, ParamSource, TypeString, args[ParamSource]) + err = kern.ErrWrongParamType(name, kern.ParamSource, kern.TypeString, args[kern.ParamSource]) } return } @@ -221,46 +223,46 @@ func lowerStrFunc(ctx ExprContext, name string, args map[string]any) (result any // --- End of function definitions // Import above functions in the context -func ImportStringFuncs(ctx ExprContext) { - ctx.RegisterFunc("strJoin", NewGolangFunctor(joinStrFunc), TypeString, []ExprFuncParam{ - NewFuncParam(ParamSeparator), - NewFuncParamFlag(ParamItem, PfRepeat), +func ImportStringFuncs(ctx kern.ExprContext) { + ctx.RegisterFunc("strJoin", kern.NewGolangFunctor(joinStrFunc), kern.TypeString, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamSeparator), + NewFuncParamFlag(kern.ParamItem, PfRepeat), }) - ctx.RegisterFunc("strSub", NewGolangFunctor(subStrFunc), TypeString, []ExprFuncParam{ - NewFuncParam(ParamSource), - NewFuncParamFlagDef(ParamStart, PfDefault, int64(0)), - NewFuncParamFlagDef(ParamCount, PfDefault, int64(-1)), + ctx.RegisterFunc("strSub", kern.NewGolangFunctor(subStrFunc), kern.TypeString, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamSource), + NewFuncParamFlagDef(kern.ParamStart, PfDefault, int64(0)), + NewFuncParamFlagDef(kern.ParamCount, PfDefault, int64(-1)), }) - ctx.RegisterFunc("strSplit", NewGolangFunctor(splitStrFunc), "list of "+TypeString, []ExprFuncParam{ - NewFuncParam(ParamSource), - NewFuncParamFlagDef(ParamSeparator, PfDefault, ""), - NewFuncParamFlagDef(ParamCount, PfDefault, int64(-1)), + ctx.RegisterFunc("strSplit", kern.NewGolangFunctor(splitStrFunc), "list of "+kern.TypeString, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamSource), + NewFuncParamFlagDef(kern.ParamSeparator, PfDefault, ""), + NewFuncParamFlagDef(kern.ParamCount, PfDefault, int64(-1)), }) - ctx.RegisterFunc("strTrim", NewGolangFunctor(trimStrFunc), TypeString, []ExprFuncParam{ - NewFuncParam(ParamSource), + ctx.RegisterFunc("strTrim", kern.NewGolangFunctor(trimStrFunc), kern.TypeString, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamSource), }) - ctx.RegisterFunc("strStartsWith", NewGolangFunctor(startsWithStrFunc), TypeBoolean, []ExprFuncParam{ - NewFuncParam(ParamSource), - NewFuncParam(ParamPrefix), + ctx.RegisterFunc("strStartsWith", kern.NewGolangFunctor(startsWithStrFunc), kern.TypeBoolean, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamSource), + NewFuncParam(kern.ParamPrefix), NewFuncParamFlag(strParamOther, PfRepeat), }) - ctx.RegisterFunc("strEndsWith", NewGolangFunctor(endsWithStrFunc), TypeBoolean, []ExprFuncParam{ - NewFuncParam(ParamSource), - NewFuncParam(ParamSuffix), + ctx.RegisterFunc("strEndsWith", kern.NewGolangFunctor(endsWithStrFunc), kern.TypeBoolean, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamSource), + NewFuncParam(kern.ParamSuffix), NewFuncParamFlag(strParamOther, PfRepeat), }) - ctx.RegisterFunc("strUpper", NewGolangFunctor(upperStrFunc), TypeString, []ExprFuncParam{ - NewFuncParam(ParamSource), + ctx.RegisterFunc("strUpper", kern.NewGolangFunctor(upperStrFunc), kern.TypeString, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamSource), }) - ctx.RegisterFunc("strLower", NewGolangFunctor(lowerStrFunc), TypeString, []ExprFuncParam{ - NewFuncParam(ParamSource), + ctx.RegisterFunc("strLower", kern.NewGolangFunctor(lowerStrFunc), kern.TypeString, []kern.ExprFuncParam{ + NewFuncParam(kern.ParamSource), }) } diff --git a/builtins-register.go b/builtins-register.go index 58305a3..d50fcc7 100644 --- a/builtins-register.go +++ b/builtins-register.go @@ -6,21 +6,23 @@ package expr import ( "fmt" + + "git.portale-stac.it/go-pkg/expr/kern" ) type builtinModule struct { - importFunc func(ExprContext) + importFunc func(kern.ExprContext) description string imported bool } -func newBuiltinModule(importFunc func(ExprContext), description string) *builtinModule { +func newBuiltinModule(importFunc func(kern.ExprContext), description string) *builtinModule { return &builtinModule{importFunc, description, false} } var builtinModuleRegister map[string]*builtinModule -func RegisterBuiltinModule(name string, importFunc func(ExprContext), description string) { +func RegisterBuiltinModule(name string, importFunc func(kern.ExprContext), description string) { if builtinModuleRegister == nil { builtinModuleRegister = make(map[string]*builtinModule) } diff --git a/data-cursor.go b/data-cursor.go index 7ed8687..923044c 100644 --- a/data-cursor.go +++ b/data-cursor.go @@ -7,11 +7,13 @@ package expr import ( "io" "slices" + + "git.portale-stac.it/go-pkg/expr/kern" ) type dataCursor struct { - ds map[string]Functor - ctx ExprContext + ds map[string]kern.Functor + ctx kern.ExprContext initState bool // true if no item has produced yet (this replace di initial Next() call in the contructor) // cursorValid bool // true if resource is nil or if clean has not yet been called index int @@ -19,12 +21,12 @@ type dataCursor struct { current any lastErr error resource any - nextFunc Functor - cleanFunc Functor - resetFunc Functor + nextFunc kern.Functor + cleanFunc kern.Functor + resetFunc kern.Functor } -func NewDataCursor(ctx ExprContext, ds map[string]Functor, resource any) (dc *dataCursor) { +func NewDataCursor(ctx kern.ExprContext, ds map[string]kern.Functor, resource any) (dc *dataCursor) { dc = &dataCursor{ ds: ds, initState: true, @@ -35,14 +37,14 @@ func NewDataCursor(ctx ExprContext, ds map[string]Functor, resource any) (dc *da lastErr: nil, resource: resource, ctx: ctx.Clone(), - nextFunc: ds[NextName], - cleanFunc: ds[CleanName], - resetFunc: ds[ResetName], + nextFunc: ds[kern.NextName], + cleanFunc: ds[kern.CleanName], + resetFunc: ds[kern.ResetName], } return } -func (dc *dataCursor) Context() ExprContext { +func (dc *dataCursor) Context() kern.ExprContext { return dc.ctx } @@ -79,27 +81,27 @@ func (dc *dataCursor) String() string { } func (dc *dataCursor) HasOperation(name string) (exists bool) { - exists = slices.Contains([]string{CleanName, ResetName, CurrentName, IndexName}, name) + exists = slices.Contains([]string{kern.CleanName, kern.ResetName, kern.CurrentName, kern.IndexName}, name) if !exists { f, ok := dc.ds[name] - exists = ok && isFunctor(f) + exists = ok && kern.IsFunctor(f) } return } func (dc *dataCursor) CallOperation(name string, args map[string]any) (value any, err error) { - if name == IndexName { + if name == kern.IndexName { value = int64(dc.Index()) - } else if name == CleanName { + } else if name == kern.CleanName { err = dc.Clean() - } else if name == ResetName { + } else if name == kern.ResetName { err = dc.Reset() - } else if functor, ok := dc.ds[name]; ok && isFunctor(functor) { - ctx := cloneContext(dc.ctx) + } else if functor, ok := dc.ds[name]; ok && kern.IsFunctor(functor) { + ctx := kern.CloneContext(dc.ctx) value, err = functor.InvokeNamed(ctx, name, args) - exportObjects(dc.ctx, ctx) + kern.ExportObjects(dc.ctx, ctx) } else { - err = errNoOperation(name) + err = kern.ErrNoOperation(name) } return } @@ -127,10 +129,10 @@ func (dc *dataCursor) CallOperation(name string, args map[string]any) (value any func (dc *dataCursor) Reset() (err error) { if dc.resetFunc != nil { - ctx := cloneContext(dc.ctx) - actualParams := bindActualParams(dc.resetFunc, []any{dc.resource}) - _, err = dc.resetFunc.InvokeNamed(ctx, ResetName, actualParams) - exportObjects(dc.ctx, ctx) + ctx := kern.CloneContext(dc.ctx) + actualParams := kern.BindActualParams(dc.resetFunc, []any{dc.resource}) + _, err = dc.resetFunc.InvokeNamed(ctx, kern.ResetName, actualParams) + kern.ExportObjects(dc.ctx, ctx) } dc.index = -1 dc.count = 0 @@ -142,10 +144,10 @@ func (dc *dataCursor) Reset() (err error) { func (dc *dataCursor) Clean() (err error) { if dc.cleanFunc != nil { - ctx := cloneContext(dc.ctx) - actualParams := bindActualParams(dc.cleanFunc, []any{dc.resource}) - _, err = dc.cleanFunc.InvokeNamed(ctx, CleanName, actualParams) - exportObjects(dc.ctx, ctx) + ctx := kern.CloneContext(dc.ctx) + actualParams := kern.BindActualParams(dc.cleanFunc, []any{dc.resource}) + _, err = dc.cleanFunc.InvokeNamed(ctx, kern.CleanName, actualParams) + kern.ExportObjects(dc.ctx, ctx) } dc.lastErr = io.EOF return @@ -178,13 +180,13 @@ func (dc *dataCursor) Current() (item any, err error) { // must return io.EOF at return } -func (dc *dataCursor) checkFilter(filter Functor, item any) (accepted bool, err error) { +func (dc *dataCursor) checkFilter(filter kern.Functor, item any) (accepted bool, err error) { var v any var ok bool - ctx := cloneContext(dc.ctx) + ctx := kern.CloneContext(dc.ctx) - actualParams := bindActualParams(filter, []any{item, dc.index}) - if v, err = filter.InvokeNamed(ctx, FilterName, actualParams); err == nil && v != nil { + actualParams := kern.BindActualParams(filter, []any{item, dc.index}) + if v, err = filter.InvokeNamed(ctx, kern.FilterName, actualParams); err == nil && v != nil { if accepted, ok = v.(bool); !ok { accepted = true // NOTE: A non-boolean value that is not nil means the item has been accepted } @@ -192,10 +194,10 @@ func (dc *dataCursor) checkFilter(filter Functor, item any) (accepted bool, err return } -func (dc *dataCursor) mapItem(mapper Functor, item any) (mappedItem any, err error) { - ctx := cloneContext(dc.ctx) - actualParams := bindActualParams(mapper, []any{item, dc.index}) - mappedItem, err = mapper.InvokeNamed(ctx, MapName, actualParams) +func (dc *dataCursor) mapItem(mapper kern.Functor, item any) (mappedItem any, err error) { + ctx := kern.CloneContext(dc.ctx) + actualParams := kern.BindActualParams(mapper, []any{item, dc.index}) + mappedItem, err = mapper.InvokeNamed(ctx, kern.MapName, actualParams) return } @@ -213,15 +215,15 @@ func (dc *dataCursor) Next() (current any, err error) { // must return io.EOF af return } current = dc.current - filter := dc.ds[FilterName] - mapper := dc.ds[MapName] + filter := dc.ds[kern.FilterName] + mapper := dc.ds[kern.MapName] var item any for item == nil && dc.lastErr == nil { - ctx := cloneContext(dc.ctx) + ctx := kern.CloneContext(dc.ctx) dc.index++ - actualParams := bindActualParams(dc.nextFunc, []any{dc.resource, dc.index}) - if item, dc.lastErr = dc.nextFunc.InvokeNamed(ctx, NextName, actualParams); dc.lastErr == nil { + actualParams := kern.BindActualParams(dc.nextFunc, []any{dc.resource, dc.index}) + if item, dc.lastErr = dc.nextFunc.InvokeNamed(ctx, kern.NextName, actualParams); dc.lastErr == nil { if item == nil { dc.lastErr = io.EOF } else { @@ -239,7 +241,7 @@ func (dc *dataCursor) Next() (current any, err error) { // must return io.EOF af } } } - exportObjects(dc.ctx, ctx) + kern.ExportObjects(dc.ctx, ctx) } dc.current = item if dc.lastErr != nil { diff --git a/dict-iterator.go b/dict-iterator.go index 442be81..59049d8 100644 --- a/dict-iterator.go +++ b/dict-iterator.go @@ -9,6 +9,8 @@ import ( "io" "slices" "strings" + + "git.portale-stac.it/go-pkg/expr/kern" ) type dictIterMode int @@ -20,7 +22,7 @@ const ( ) type DictIterator struct { - a *DictType + a *kern.DictType count int index int keys []any @@ -65,7 +67,7 @@ func (it *DictIterator) makeKeys(m map[any]any, sort sortType) { } } -func NewDictIterator(dict *DictType, args []any) (it *DictIterator, err error) { +func NewDictIterator(dict *kern.DictType, args []any) (it *DictIterator, err error) { var sortType = sortTypeNone var s string var argAny any @@ -76,7 +78,7 @@ func NewDictIterator(dict *DictType, args []any) (it *DictIterator, err error) { } else { argAny = "default" } - if s, err = ToGoString(argAny, "sort type"); err == nil { + if s, err = kern.ToGoString(argAny, "sort type"); err == nil { switch strings.ToLower(s) { case "a", "asc": sortType = sortTypeAsc @@ -97,7 +99,7 @@ func NewDictIterator(dict *DictType, args []any) (it *DictIterator, err error) { argAny = "default" } - if s, err = ToGoString(argAny, "iteration mode"); err == nil { + if s, err = kern.ToGoString(argAny, "iteration mode"); err == nil { switch strings.ToLower(s) { case "k", "key", "keys": dictIt.iterMode = dictIterModeKeys @@ -119,7 +121,7 @@ func NewDictIterator(dict *DictType, args []any) (it *DictIterator, err error) { } func NewMapIterator(m map[any]any) (it *DictIterator) { - it = &DictIterator{a: (*DictType)(&m), count: 0, index: -1, keys: nil} + it = &DictIterator{a: (*kern.DictType)(&m), count: 0, index: -1, keys: nil} it.makeKeys(m, sortTypeNone) return } @@ -138,31 +140,31 @@ func (it *DictIterator) TypeName() string { func (it *DictIterator) HasOperation(name string) bool { // yes := name == NextName || name == ResetName || name == IndexName || name == CountName || name == CurrentName - yes := slices.Contains([]string{NextName, ResetName, IndexName, CountName, CurrentName, CleanName, KeyName, ValueName}, name) + yes := slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName, kern.CleanName, kern.KeyName, kern.ValueName}, name) return yes } func (it *DictIterator) CallOperation(name string, args map[string]any) (v any, err error) { switch name { - case NextName: + case kern.NextName: v, err = it.Next() - case ResetName: + case kern.ResetName: err = it.Reset() - case CleanName: + case kern.CleanName: err = it.Clean() - case IndexName: + case kern.IndexName: v = int64(it.Index()) - case CurrentName: + case kern.CurrentName: v, err = it.Current() - case CountName: + case kern.CountName: v = it.count - case KeyName: + case kern.KeyName: if it.index >= 0 && it.index < len(it.keys) { v = it.keys[it.index] } else { err = io.EOF } - case ValueName: + case kern.ValueName: if it.index >= 0 && it.index < len(it.keys) { a := *(it.a) v = a[it.keys[it.index]] @@ -170,7 +172,7 @@ func (it *DictIterator) CallOperation(name string, args map[string]any) (v any, err = io.EOF } default: - err = errNoOperation(name) + err = kern.ErrNoOperation(name) } return } @@ -186,7 +188,7 @@ func (it *DictIterator) Current() (item any, err error) { case dictIterModeItems: a := *(it.a) pair := []any{it.keys[it.index], a[it.keys[it.index]]} - item = newList(pair) + item = kern.NewList(pair) } } else { err = io.EOF diff --git a/doc/Expr.adoc b/doc/Expr.adoc index c1f0e64..5e1da70 100644 --- a/doc/Expr.adoc +++ b/doc/Expr.adoc @@ -1421,12 +1421,38 @@ Same as <<_add,add()>> but returns the product of the values of the parameters. [green]`24` ==== Module "os.file" +The "os.file" module provides functions for working with files. + +Activation: + +`{4sp}builtin "os.file"` + +Currently available functions: + +* <<_fileOpen,fileOpen()>> +* <<_fileAppend,fileAppend()>> +* <<_fileCreate,fileCreate()>> +* <<_fileClose,fileClose()>> +* <<_fileWriteText,fileWriteText()>> +* <<_fileReadText,fileReadText()>> +* <<_fileReadTextAll,fileReadTextAll()>> + +More functions will be added in the future. + +--- ===== fileOpen() +Syntax: + +`{4sp}fileOpen() -> file-handle` + +Returns a file handle for the specified file path. The file is opened in read-write mode. If the file does not exist, it is created. ===== fileAppend() ===== fileCreate() +Syntax: + +`{4sp}fileCreate() -> file-handle` + +Creates or truncates the named __. If the file already exists, it is truncated. If the file does not exist, it is created with mode 0o666 (before umask). The associated file descriptor has mode [O_RDWR]. The directory containing the file must already exist. ===== fileClose() @@ -1438,6 +1464,24 @@ Same as <<_add,add()>> but returns the product of the values of the parameters. ==== Module "string" +This module provides functions for working with strings. + +Activation: + +`{4sp}builtin "string"` + + +Currently available functions: + +* <<_strJoin,strJoin()>> +* <<_strSub,strSub()>> +* <<_strSplit,strSplit()>> +* <<_strTrim,strTrim()>> +* <<_strStartsWith,strStartsWith()>> +* <<_strEndsWith,strEndsWith()>> +* <<_strUpper,strUpper()>> +* <<_strLower,strLower()>> + +--- ===== strJoin() Syntax: + diff --git a/expr.go b/expr.go index 730e149..5323181 100644 --- a/expr.go +++ b/expr.go @@ -4,9 +4,13 @@ // expr.go package expr +import ( + kern "git.portale-stac.it/go-pkg/expr/kern" +) + // ----Expression interface type Expr interface { - Typer - Eval(ctx ExprContext) (result any, err error) + kern.Typer + Eval(ctx kern.ExprContext) (result any, err error) String() string } diff --git a/function.go b/function.go index 11c5602..640cd8b 100644 --- a/function.go +++ b/function.go @@ -6,19 +6,20 @@ package expr import ( "fmt" - "strconv" "strings" + + "git.portale-stac.it/go-pkg/expr/kern" ) // ---- Function template -type FuncTemplate func(ctx ExprContext, name string, args map[string]any) (result any, err error) +// type FuncTemplate func(ctx expr.ExprContext, name string, args map[string]any) (result any, err error) // ---- Common functor definition -type baseFunctor struct { - info ExprFunc +type BaseFunctor struct { + info kern.ExprFunc } -func (functor *baseFunctor) ToString(opt FmtOpt) (s string) { +func (functor *BaseFunctor) ToString(opt kern.FmtOpt) (s string) { if functor.info != nil { s = functor.info.ToString(opt) } else { @@ -27,23 +28,23 @@ func (functor *baseFunctor) ToString(opt FmtOpt) (s string) { return s } -func (functor *baseFunctor) GetParams() (params []ExprFuncParam) { +func (functor *BaseFunctor) GetParams() (params []kern.ExprFuncParam) { if functor.info != nil { return functor.info.Params() } else { - return []ExprFuncParam{} + return []kern.ExprFuncParam{} } } -func (functor *baseFunctor) SetFunc(info ExprFunc) { +func (functor *BaseFunctor) SetFunc(info kern.ExprFunc) { functor.info = info } -func (functor *baseFunctor) GetFunc() ExprFunc { +func (functor *BaseFunctor) GetFunc() kern.ExprFunc { return functor.info } -func (functor *baseFunctor) GetDefinitionContext() ExprContext { +func (functor *BaseFunctor) GetDefinitionContext() kern.ExprContext { return nil } @@ -62,11 +63,11 @@ type funcParamInfo struct { defaultValue any } -func NewFuncParam(name string) ExprFuncParam { +func NewFuncParam(name string) kern.ExprFuncParam { return &funcParamInfo{name: name} } -func NewFuncParamFlag(name string, flags paramFlags) ExprFuncParam { +func NewFuncParamFlag(name string, flags paramFlags) kern.ExprFuncParam { return &funcParamInfo{name: name, flags: flags} } @@ -79,7 +80,7 @@ func (param *funcParamInfo) Name() string { } func (param *funcParamInfo) Type() string { - return TypeAny + return kern.TypeAny } func (param *funcParamInfo) IsDefault() bool { @@ -100,17 +101,17 @@ func (param *funcParamInfo) DefaultValue() any { // --- Functions -// funcInfo implements ExprFunc +// funcInfo implements expr.ExprFunc type funcInfo struct { name string minArgs int maxArgs int - functor Functor - formalParams []ExprFuncParam + functor kern.Functor + formalParams []kern.ExprFuncParam returnType string } -func newFuncInfo(name string, functor Functor, returnType string, params []ExprFuncParam) (info *funcInfo, err error) { +func newFuncInfo(name string, functor kern.Functor, returnType string, params []kern.ExprFuncParam) (info *funcInfo, err error) { var minArgs = 0 var maxArgs = 0 for _, p := range params { @@ -138,7 +139,7 @@ func newFuncInfo(name string, functor Functor, returnType string, params []ExprF return info, nil } -func (info *funcInfo) Params() []ExprFuncParam { +func (info *funcInfo) Params() []kern.ExprFuncParam { return info.formalParams } @@ -146,7 +147,7 @@ func (info *funcInfo) ReturnType() string { return info.returnType } -func (info *funcInfo) ToString(opt FmtOpt) string { +func (info *funcInfo) ToString(opt kern.FmtOpt) string { var sb strings.Builder if len(info.Name()) == 0 { sb.WriteString("func") @@ -180,7 +181,7 @@ func (info *funcInfo) ToString(opt FmtOpt) string { if len(info.returnType) > 0 { sb.WriteString(info.returnType) } else { - sb.WriteString(TypeAny) + sb.WriteString(kern.TypeAny) } sb.WriteString("{}") return sb.String() @@ -198,11 +199,11 @@ func (info *funcInfo) MaxArgs() int { return info.maxArgs } -func (info *funcInfo) Functor() Functor { +func (info *funcInfo) Functor() kern.Functor { return info.functor } -func (info *funcInfo) AllocContext(parentCtx ExprContext) (ctx ExprContext) { +func (info *funcInfo) AllocContext(parentCtx kern.ExprContext) (ctx kern.ExprContext) { if defCtx := info.functor.GetDefinitionContext(); defCtx != nil { ctx = defCtx.Clone() ctx.SetParent(defCtx) @@ -213,7 +214,7 @@ func (info *funcInfo) AllocContext(parentCtx ExprContext) (ctx ExprContext) { return } -func (info *funcInfo) ParamSpec(paramName string) ExprFuncParam { +func (info *funcInfo) ParamSpec(paramName string) kern.ExprFuncParam { for _, spec := range info.formalParams { if spec.Name() == paramName { return spec @@ -222,7 +223,7 @@ func (info *funcInfo) ParamSpec(paramName string) ExprFuncParam { return nil } -func initActualParams(ctx ExprContext, info ExprFunc, callTerm *term) (actualParams map[string]any, err error) { +func initActualParams(ctx kern.ExprContext, info kern.ExprFunc, callTerm *term) (actualParams map[string]any, err error) { var varArgs []any var varName string @@ -237,10 +238,10 @@ func initActualParams(ctx ExprContext, info ExprFunc, callTerm *term) (actualPar for i, tree := range callTerm.children { var paramValue any paramCtx := ctx.Clone() - if paramValue, err = tree.compute(paramCtx); err != nil { + if paramValue, err = tree.Compute(paramCtx); err != nil { break } - if paramName, namedParam := getAssignVarName(tree); namedParam { + if paramName, namedParam := kern.GetAssignVarName(tree); namedParam { if info.ParamSpec(paramName) == nil { err = fmt.Errorf("%s(): unknown param %q", info.Name(), paramName) break @@ -260,7 +261,7 @@ func initActualParams(ctx ExprContext, info ExprFunc, callTerm *term) (actualPar actualParams[spec.Name()] = paramValue } } else { - err = ErrTooManyParams(info.Name(), len(formalParams), len(callTerm.children)) + err = kern.ErrTooManyParams(info.Name(), len(formalParams), len(callTerm.children)) break } } else { @@ -279,7 +280,7 @@ func initActualParams(ctx ExprContext, info ExprFunc, callTerm *term) (actualPar func (info *funcInfo) PrepareCall(name string, actualParams map[string]any) (err error) { passedCount := len(actualParams) if info.MinArgs() > passedCount { - err = ErrTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount) + err = kern.ErrTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount) return } @@ -301,86 +302,86 @@ func (info *funcInfo) PrepareCall(name string, actualParams map[string]any) (err } if info.MaxArgs() >= 0 && info.MaxArgs() < len(actualParams) { - err = ErrTooManyParams(name, info.MaxArgs(), len(actualParams)) + err = kern.ErrTooManyParams(name, info.MaxArgs(), len(actualParams)) } return } // ----- Call a function --- -func getAssignVarName(t *term) (name string, ok bool) { - if ok = t.symbol() == SymEqual; ok { - name = t.children[0].source() - } - return -} +// func getAssignVarName(t *term) (name string, ok bool) { +// if ok = t.symbol() == SymEqual; ok { +// name = t.children[0].source() +// } +// return +// } -func CallFunctionByTerm(parentCtx ExprContext, name string, callTerm *term) (result any, err error) { - var actualParams map[string]any - if info, exists := GetFuncInfo(parentCtx, name); exists { - if actualParams, err = initActualParams(parentCtx, info, callTerm); err == nil { - ctx := info.AllocContext(parentCtx) - if err = info.PrepareCall(name, actualParams); err == nil { - functor := info.Functor() - result, err = functor.InvokeNamed(ctx, name, actualParams) - exportObjectsToParent(ctx) - } - } - } else { - err = fmt.Errorf("unknown function %s()", name) - } - return -} +// func CallFunctionByTerm(parentCtx expr.ExprContext, name string, callTerm *term) (result any, err error) { +// var actualParams map[string]any +// if info, exists := GetFuncInfo(parentCtx, name); exists { +// if actualParams, err = initActualParams(parentCtx, info, callTerm); err == nil { +// ctx := info.AllocContext(parentCtx) +// if err = info.PrepareCall(name, actualParams); err == nil { +// functor := info.Functor() +// result, err = functor.InvokeNamed(ctx, name, actualParams) +// exportObjectsToParent(ctx) +// } +// } +// } else { +// err = fmt.Errorf("unknown function %s()", name) +// } +// return +// } -func CallFunctionByArgs(parentCtx ExprContext, name string, args []any) (result any, err error) { - var actualParams map[string]any - if info, exists := GetFuncInfo(parentCtx, name); exists { - functor := info.Functor() - actualParams = bindActualParams(functor, args) - ctx := info.AllocContext(parentCtx) - if err = info.PrepareCall(name, actualParams); err == nil { - result, err = functor.InvokeNamed(ctx, name, actualParams) - exportObjectsToParent(ctx) - } - } else { - err = fmt.Errorf("unknown function %s()", name) - } - return -} +// func CallFunctionByArgs(parentCtx expr.ExprContext, name string, args []any) (result any, err error) { +// var actualParams map[string]any +// if info, exists := GetFuncInfo(parentCtx, name); exists { +// functor := info.Functor() +// actualParams = bindActualParams(functor, args) +// ctx := info.AllocContext(parentCtx) +// if err = info.PrepareCall(name, actualParams); err == nil { +// result, err = functor.InvokeNamed(ctx, name, actualParams) +// exportObjectsToParent(ctx) +// } +// } else { +// err = fmt.Errorf("unknown function %s()", name) +// } +// return +// } -func CallFunctionByParams(parentCtx ExprContext, name string, actualParams map[string]any) (result any, err error) { - //var actualParams map[string]any - if info, exists := GetFuncInfo(parentCtx, name); exists { - functor := info.Functor() - ctx := info.AllocContext(parentCtx) - if err = info.PrepareCall(name, actualParams); err == nil { - result, err = functor.InvokeNamed(ctx, name, actualParams) - exportObjectsToParent(ctx) - } - } else { - err = fmt.Errorf("unknown function %s()", name) - } - return -} +// func CallFunctionByParams(parentCtx expr.ExprContext, name string, actualParams map[string]any) (result any, err error) { +// //var actualParams map[string]any +// if info, exists := GetFuncInfo(parentCtx, name); exists { +// functor := info.Functor() +// ctx := info.AllocContext(parentCtx) +// if err = info.PrepareCall(name, actualParams); err == nil { +// result, err = functor.InvokeNamed(ctx, name, actualParams) +// exportObjectsToParent(ctx) +// } +// } else { +// err = fmt.Errorf("unknown function %s()", name) +// } +// return +// } -func GetParam(args map[string]any, paramName string, paramNum int) (value any, exists bool) { - if value, exists = args[paramName]; !exists { - if paramNum > 0 && paramNum <= len(args) { - value, exists = args["arg"+strconv.Itoa(paramNum)] - } - } - return -} +// func GetParam(args map[string]any, paramName string, paramNum int) (value any, exists bool) { +// if value, exists = args[paramName]; !exists { +// if paramNum > 0 && paramNum <= len(args) { +// value, exists = args["arg"+strconv.Itoa(paramNum)] +// } +// } +// return +// } -func bindActualParams(functor Functor, args []any) (actualParams map[string]any) { - formalParams := functor.GetParams() - actualParams = make(map[string]any, len(args)) - for i, arg := range args { - if i < len(formalParams) { - actualParams[formalParams[i].Name()] = arg - } else { - actualParams["arg"+strconv.Itoa(i+1)] = arg - } - } - return -} +// func bindActualParams(functor Functor, args []any) (actualParams map[string]any) { +// formalParams := functor.GetParams() +// actualParams = make(map[string]any, len(args)) +// for i, arg := range args { +// if i < len(formalParams) { +// actualParams[formalParams[i].Name()] = arg +// } else { +// actualParams["arg"+strconv.Itoa(i+1)] = arg +// } +// } +// return +// } diff --git a/global-context.go b/global-context.go index acab4af..4f3e547 100644 --- a/global-context.go +++ b/global-context.go @@ -7,101 +7,68 @@ package expr import ( "path/filepath" "strings" + + "git.portale-stac.it/go-pkg/expr/kern" ) -var globalCtx *SimpleStore +//var globalCtx *SimpleStore -func ImportInContext(name string) (exists bool) { - var mod *builtinModule - if mod, exists = builtinModuleRegister[name]; exists { - mod.importFunc(globalCtx) - mod.imported = true +func ImportInContext(ctx kern.ExprContext, name string) (exists bool) { + if globalCtx := ctx.GetGlobal(); globalCtx != nil { + var mod *builtinModule + if mod, exists = builtinModuleRegister[name]; exists { + mod.importFunc(globalCtx) + mod.imported = true + } } return } -func ImportInContextByGlobPattern(pattern string) (count int, err error) { - var matched bool - for name, mod := range builtinModuleRegister { - if matched, err = filepath.Match(pattern, name); err == nil { - if matched { - count++ - mod.importFunc(globalCtx) - mod.imported = true +func ImportInContextByGlobPattern(ctx kern.ExprContext, pattern string) (count int, err error) { + if globalCtx := ctx.GetGlobal(); globalCtx != nil { + var matched bool + for name, mod := range builtinModuleRegister { + if matched, err = filepath.Match(pattern, name); err == nil { + if matched { + count++ + mod.importFunc(globalCtx) + mod.imported = true + } + } else { + break } - } else { - break } } return } -func GetVar(ctx ExprContext, name string) (value any, exists bool) { - if value, exists = ctx.GetVar(name); !exists { - value, exists = globalCtx.GetVar(name) - } - return -} - -func GetLocalFuncInfo(ctx ExprContext, name string) (item ExprFunc, exists bool) { - var v any - if len(name) > 0 { - if v, exists = ctx.GetVar(name); exists && isFunctor(v) { - f, _ := v.(Functor) - item = f.GetFunc() - } else { - item, exists = ctx.GetFuncInfo(name) +func GlobalCtrlSet(ctx kern.ExprContext, name string, newValue any) (currentValue any) { + if globalCtx := ctx.GetGlobal(); globalCtx != nil { + if !strings.HasPrefix(name, "_") { + name = "_" + name } + + currentValue, _ = globalCtx.GetVar(name) + globalCtx.SetVar(name, newValue) } - return -} - -func GetFuncInfo(ctx ExprContext, name string) (item ExprFunc, exists bool) { - // if len(name) > 0 { - // if item, exists = GetLocalFuncInfo(ctx, name); exists { - // ownerCtx = ctx - // } else if item, exists = globalCtx.GetFuncInfo(name); exists { - // ownerCtx = globalCtx - // } - // } - item, exists, _ = GetFuncInfoAndOwner(ctx, name) - return -} - -func GetFuncInfoAndOwner(ctx ExprContext, name string) (item ExprFunc, exists bool, ownerCtx ExprContext) { - if len(name) > 0 { - if item, exists = GetLocalFuncInfo(ctx, name); exists { - ownerCtx = ctx - } else if item, exists = globalCtx.GetFuncInfo(name); exists { - ownerCtx = globalCtx - } - } - return -} - -func GlobalCtrlSet(name string, newValue any) (currentValue any) { - if !strings.HasPrefix(name, "_") { - name = "_" + name - } - currentValue, _ = globalCtx.GetVar(name) - - globalCtx.SetVar(name, newValue) return currentValue } -func GlobalCtrlGet(name string) (currentValue any) { - if !strings.HasPrefix(name, "_") { - name = "_" + name +func GlobalCtrlGet(ctx kern.ExprContext, name string) (currentValue any) { + if globalCtx := ctx.GetGlobal(); globalCtx != nil { + if !strings.HasPrefix(name, "_") { + name = "_" + name + } + currentValue, _ = globalCtx.GetVar(name) } - currentValue, _ = globalCtx.GetVar(name) return currentValue } -func CtrlEnable(ctx ExprContext, name string) (currentStatus bool) { +func CtrlEnable(ctx kern.ExprContext, name string) (currentStatus bool) { if !strings.HasPrefix(name, "_") { name = "_" + name } - if v, exists := ctx.GetVar(name); exists && IsBool(v) { + if v, exists := ctx.GetVar(name); exists && kern.IsBool(v) { currentStatus, _ = v.(bool) } @@ -109,11 +76,11 @@ func CtrlEnable(ctx ExprContext, name string) (currentStatus bool) { return currentStatus } -func CtrlDisable(ctx ExprContext, name string) (currentStatus bool) { +func CtrlDisable(ctx kern.ExprContext, name string) (currentStatus bool) { if !strings.HasPrefix(name, "_") { name = "_" + name } - if v, exists := ctx.GetVar(name); exists && IsBool(v) { + if v, exists := ctx.GetVar(name); exists && kern.IsBool(v) { currentStatus, _ = v.(bool) } @@ -121,36 +88,39 @@ func CtrlDisable(ctx ExprContext, name string) (currentStatus bool) { return currentStatus } -func CtrlIsEnabled(ctx ExprContext, name string) (status bool) { - var v any - var exists bool +// func CtrlIsEnabled(ctx ExprContext, name string) (status bool) { +// var v any +// var exists bool - if !strings.HasPrefix(name, "_") { - name = "_" + name - } +// if !strings.HasPrefix(name, "_") { +// name = "_" + name +// } - if v, exists = ctx.GetVar(name); !exists { - v, exists = globalCtx.GetVar(name) - } +// if v, exists = ctx.GetVar(name); !exists { +// v, exists = globalCtx.GetVar(name) +// } - if exists { - if b, ok := v.(bool); ok { - status = b +// if exists { +// if b, ok := v.(bool); ok { +// status = b +// } +// } +// return +// } + +func getControlString(ctx kern.ExprContext, name string) (s string, exists bool) { + if globalCtx := ctx.GetGlobal(); globalCtx != nil { + var v any + if v, exists = globalCtx.GetVar(name); exists { + s, exists = v.(string) } } return } -func getControlString(name string) (s string, exists bool) { - var v any - if v, exists = globalCtx.GetVar(name); exists { - s, exists = v.(string) - } +func InitGlobal() (ctx kern.ExprContext) { + ctx = NewSimpleStoreWithoutGlobalContext() + kern.InitDefaultVars(ctx) + ImportBuiltinsFuncs(ctx) return } - -func init() { - globalCtx = NewSimpleStore() - initDefaultVars(globalCtx) - ImportBuiltinsFuncs(globalCtx) -} diff --git a/graph.go b/graph.go index 92c31a3..f5ad7bb 100644 --- a/graph.go +++ b/graph.go @@ -53,7 +53,7 @@ func (r *Reticle) computeCharWidth() { if v := ref.node.value(); v != nil { ref.label = fmt.Sprintf("%v", v) } else { - ref.label = ref.node.source() + ref.label = ref.node.Source() } r.colsWidth[c] = max(r.colsWidth[c], len(ref.label)+2) // +2 to make room for brakets } diff --git a/helpers.go b/helpers.go index f25fa10..49922de 100644 --- a/helpers.go +++ b/helpers.go @@ -9,9 +9,11 @@ import ( "io" "os" "strings" + + "git.portale-stac.it/go-pkg/expr/kern" ) -func EvalString(ctx ExprContext, source string) (result any, err error) { +func EvalString(ctx kern.ExprContext, source string) (result any, err error) { var tree *ast r := strings.NewReader(source) @@ -34,21 +36,21 @@ func EvalStringA(source string, args ...Arg) (result any, err error) { } func EvalStringV(source string, args []Arg) (result any, err error) { - ctx := NewSimpleStore() + ctx := NewSimpleStoreWithoutGlobalContext() for _, arg := range args { - if isFunc(arg.Value) { - if f, ok := arg.Value.(FuncTemplate); ok { - functor := NewGolangFunctor(f) + if kern.IsFunc(arg.Value) { + if f, ok := arg.Value.(kern.FuncTemplate); ok { + functor := kern.NewGolangFunctor(f) // ctx.RegisterFunc(arg.Name, functor, 0, -1) - ctx.RegisterFunc(arg.Name, functor, TypeAny, []ExprFuncParam{ - NewFuncParamFlagDef(ParamValue, PfDefault|PfRepeat, 0), + ctx.RegisterFunc(arg.Name, functor, kern.TypeAny, []kern.ExprFuncParam{ + NewFuncParamFlagDef(kern.ParamValue, PfDefault|PfRepeat, 0), }) } else { err = fmt.Errorf("invalid function specification: %q", arg.Name) } - } else if integer, ok := anyInteger(arg.Value); ok { + } else if integer, ok := kern.AnyInteger(arg.Value); ok { ctx.SetVar(arg.Name, integer) - } else if float, ok := anyFloat(arg.Value); ok { + } else if float, ok := kern.AnyFloat(arg.Value); ok { ctx.SetVar(arg.Name, float) } else if _, ok := arg.Value.(string); ok { ctx.SetVar(arg.Name, arg.Value) @@ -65,7 +67,7 @@ func EvalStringV(source string, args []Arg) (result any, err error) { return } -func EvalStream(ctx ExprContext, r io.Reader) (result any, err error) { +func EvalStream(ctx kern.ExprContext, r io.Reader) (result any, err error) { var tree *ast scanner := NewScanner(r, DefaultTranslations()) parser := NewParser() @@ -76,7 +78,7 @@ func EvalStream(ctx ExprContext, r io.Reader) (result any, err error) { return } -func EvalFile(ctx ExprContext, filePath string) (result any, err error) { +func EvalFile(ctx kern.ExprContext, filePath string) (result any, err error) { var fh *os.File if fh, err = os.Open(filePath); err != nil { return nil, err diff --git a/import-utils.go b/import-utils.go index 5755ae5..0d0d766 100644 --- a/import-utils.go +++ b/import-utils.go @@ -11,6 +11,8 @@ import ( "path" "path/filepath" "strings" + + "git.portale-stac.it/go-pkg/expr/kern" ) const ( @@ -19,8 +21,8 @@ const ( ) func checkStringParamExpected(funcName string, paramValue any, paramPos int) (err error) { - if !(IsString(paramValue) /*|| isList(paramValue)*/) { - err = fmt.Errorf("%s(): param nr %d has wrong type %s, string expected", funcName, paramPos+1, TypeName(paramValue)) + if !(kern.IsString(paramValue) /*|| isList(paramValue)*/) { + err = fmt.Errorf("%s(): param nr %d has wrong type %s, string expected", funcName, paramPos+1, kern.TypeName(paramValue)) } return } @@ -45,8 +47,8 @@ func addEnvImportDirs(envVarName string, dirList []string) []string { return dirList } -func addSearchDirs(endingPath string, dirList []string) []string { - if dirSpec, exists := getControlString(ControlSearchPath); exists { +func addSearchDirs(ctx kern.ExprContext, endingPath string, dirList []string) []string { + if dirSpec, exists := getControlString(ctx, kern.ControlSearchPath); exists { dirs := strings.Split(dirSpec, ":") if dirList == nil { dirList = dirs @@ -63,9 +65,9 @@ func addSearchDirs(endingPath string, dirList []string) []string { return dirList } -func buildSearchDirList(endingPath, envVarName string) (dirList []string) { +func buildSearchDirList(ctx kern.ExprContext, endingPath, envVarName string) (dirList []string) { dirList = addEnvImportDirs(envVarName, dirList) - dirList = addSearchDirs(endingPath, dirList) + dirList = addSearchDirs(ctx, endingPath, dirList) return } @@ -83,7 +85,7 @@ func searchAmongPath(filename string, dirList []string) (filePath string) { } for _, dir := range dirList { - if dir, err = ExpandPath(dir); err != nil { + if dir, err = kern.ExpandPath(dir); err != nil { continue } if fullPath := path.Join(dir, filename); isFile(fullPath) { @@ -106,7 +108,7 @@ func isPathRelative(filePath string) bool { } func makeFilepath(filename string, dirList []string) (filePath string, err error) { - if filename, err = ExpandPath(filename); err != nil { + if filename, err = kern.ExpandPath(filename); err != nil { return } diff --git a/iter-factory.go b/iter-factory.go index 1a36b15..268a8fb 100644 --- a/iter-factory.go +++ b/iter-factory.go @@ -4,19 +4,23 @@ // iter-factory.go package expr -func NewIterator(value any) (it Iterator, err error) { +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + +func NewIterator(value any) (it kern.Iterator, err error) { if value == nil { return NewArrayIterator([]any{}), nil } switch v := value.(type) { - case *ListType: + case *kern.ListType: it = NewListIterator(v, nil) - case *DictType: + case *kern.DictType: it, err = NewDictIterator(v, nil) case []any: it = NewArrayIterator(v) - case Iterator: + case kern.Iterator: it = v default: it = NewArrayIterator([]any{value}) diff --git a/bind-go-functions.go b/kern/bind-go-functions.go similarity index 95% rename from bind-go-functions.go rename to kern/bind-go-functions.go index 46cf8d0..7c2866e 100644 --- a/bind-go-functions.go +++ b/kern/bind-go-functions.go @@ -2,11 +2,11 @@ // All rights reserved. // bind-go-function.go -package expr +package kern // ---- Linking with Go functions type golangFunctor struct { - baseFunctor + BaseFunctor f FuncTemplate } diff --git a/common-errors.go b/kern/common-errors.go similarity index 96% rename from common-errors.go rename to kern/common-errors.go index f0b6973..1884898 100644 --- a/common-errors.go +++ b/kern/common-errors.go @@ -2,7 +2,7 @@ // All rights reserved. // common-errors.go -package expr +package kern import ( "fmt" @@ -86,6 +86,6 @@ func ErrUnknownVar(funcName, varName string) error { // --- Operator errors -func ErrLeftOperandMustBeVariable(leftTerm, opTerm *term) error { - return leftTerm.Errorf("left operand of %q must be a variable", opTerm.source()) +func ErrLeftOperandMustBeVariable(leftTerm, opTerm Term) error { + return leftTerm.Errorf("left operand of %q must be a variable", opTerm.Source()) } diff --git a/common-params.go b/kern/common-params.go similarity index 98% rename from common-params.go rename to kern/common-params.go index 38279f2..37df826 100644 --- a/common-params.go +++ b/kern/common-params.go @@ -2,7 +2,7 @@ // All rights reserved. // common-params.go -package expr +package kern const ( ParamArgs = "args" diff --git a/common-type-names.go b/kern/common-type-names.go similarity index 97% rename from common-type-names.go rename to kern/common-type-names.go index 0595a1d..09a1979 100644 --- a/common-type-names.go +++ b/kern/common-type-names.go @@ -2,7 +2,7 @@ // All rights reserved. // common-type-names.go -package expr +package kern const ( TypeAny = "any" diff --git a/context-helpers.go b/kern/context-helpers.go similarity index 84% rename from context-helpers.go rename to kern/context-helpers.go index e30194a..b6bc360 100644 --- a/context-helpers.go +++ b/kern/context-helpers.go @@ -2,9 +2,9 @@ // All rights reserved. // context-helpers.go -package expr +package kern -func cloneContext(sourceCtx ExprContext) (clonedCtx ExprContext) { +func CloneContext(sourceCtx ExprContext) (clonedCtx ExprContext) { if sourceCtx != nil { clonedCtx = sourceCtx.Clone() } @@ -25,8 +25,8 @@ func exportFunc(ctx ExprContext, name string, info ExprFunc) { ctx.RegisterFunc(name, info.Functor(), info.ReturnType(), info.Params()) } -func exportObjects(destCtx, sourceCtx ExprContext) { - exportAll := CtrlIsEnabled(sourceCtx, control_export_all) +func ExportObjects(destCtx, sourceCtx ExprContext) { + exportAll := CtrlIsEnabled(sourceCtx, ControlExportAll) // fmt.Printf("Exporting from sourceCtx [%p] to destCtx [%p] -- exportAll=%t\n", sourceCtx, destCtx, exportAll) // Export variables for _, refName := range sourceCtx.EnumVars(func(name string) bool { return (exportAll || name[0] == '@') && !(name[0] == '_') }) { @@ -44,6 +44,6 @@ func exportObjects(destCtx, sourceCtx ExprContext) { func exportObjectsToParent(sourceCtx ExprContext) { if parentCtx := sourceCtx.GetParent(); parentCtx != nil { - exportObjects(parentCtx, sourceCtx) + ExportObjects(parentCtx, sourceCtx) } } diff --git a/control.go b/kern/control.go similarity index 64% rename from control.go rename to kern/control.go index 1c4edeb..309d3a6 100644 --- a/control.go +++ b/kern/control.go @@ -2,7 +2,9 @@ // All rights reserved. // control.go -package expr +package kern + +import "strings" // Preset control variables const ( @@ -16,7 +18,7 @@ const ( // Other control variables const ( - control_export_all = "_export_all" + ControlExportAll = "_export_all" ) // Initial values @@ -24,13 +26,34 @@ const ( init_search_path = "~/.local/lib/go-pkg/expr:/usr/local/lib/go-pkg/expr:/usr/lib/go-pkg/expr" ) +func CtrlIsEnabled(ctx ExprContext, name string) (status bool) { + var v any + var exists bool + + if !strings.HasPrefix(name, "_") { + name = "_" + name + } + + if v, exists = ctx.GetVar(name); !exists { + if globalCtx := ctx.GetGlobal(); globalCtx != nil { + v, exists = globalCtx.GetVar(name) + } + } + + if exists { + if b, ok := v.(bool); ok { + status = b + } + } + return +} func SetCtrl(ctx ExprContext, name string, value any) (current any) { current, _ = ctx.GetVar(name) ctx.UnsafeSetVar(name, value) return } -func initDefaultVars(ctx ExprContext) { +func InitDefaultVars(ctx ExprContext) { if _, exists := ctx.GetVar(ControlPreset); exists { return } diff --git a/dict-type.go b/kern/dict-type.go similarity index 90% rename from dict-type.go rename to kern/dict-type.go index ebbd53c..94c67fe 100644 --- a/dict-type.go +++ b/kern/dict-type.go @@ -2,7 +2,7 @@ // All rights reserved. // dict-type.go -package expr +package kern import ( "fmt" @@ -32,7 +32,7 @@ func NewDict(dictAny map[any]any) (dict *DictType) { return } -func newDict(dictAny map[any]*term) (dict *DictType) { +func newDict(dictAny map[any]Term) (dict *DictType) { // TODO Change with a call to NewDict() var d DictType if dictAny != nil { @@ -110,7 +110,7 @@ func (dict *DictType) ToString(opt FmtOpt) string { sb.WriteString(": ") if formatter, ok := value.(Formatter); ok { sb.WriteString(formatter.ToString(opt)) - } else if t, ok := value.(*term); ok { + } else if t, ok := value.(Term); ok { sb.WriteString(t.String()) } else { sb.WriteString(fmt.Sprintf("%#v", value)) @@ -129,7 +129,7 @@ func (dict *DictType) TypeName() string { return "dict" } -func (dict *DictType) hasKey(target any) (ok bool) { +func (dict *DictType) HasKey(target any) (ok bool) { for key := range *dict { if ok = reflect.DeepEqual(key, target); ok { break @@ -138,7 +138,7 @@ func (dict *DictType) hasKey(target any) (ok bool) { return } -func (dict *DictType) clone() (c *DictType) { +func (dict *DictType) Clone() (c *DictType) { c = newDict(nil) for k, v := range *dict { (*c)[k] = v @@ -146,7 +146,7 @@ func (dict *DictType) clone() (c *DictType) { return } -func (dict *DictType) merge(second *DictType) { +func (dict *DictType) Merge(second *DictType) { if second != nil { for k, v := range *second { (*dict)[k] = v @@ -154,7 +154,7 @@ func (dict *DictType) merge(second *DictType) { } } -func (dict *DictType) setItem(key any, value any) (err error) { +func (dict *DictType) SetItem(key any, value any) (err error) { (*dict)[key] = value return } diff --git a/expr-context.go b/kern/expr-context.go similarity index 89% rename from expr-context.go rename to kern/expr-context.go index 5e73c9c..e1d72ef 100644 --- a/expr-context.go +++ b/kern/expr-context.go @@ -2,13 +2,14 @@ // All rights reserved. // expr-context.go -package expr +package kern // ----Expression Context type ExprContext interface { Clone() ExprContext SetParent(ctx ExprContext) GetParent() (ctx ExprContext) + GetGlobal() (ctx ExprContext) GetVar(varName string) (value any, exists bool) GetLast() any SetVar(varName string, value any) @@ -22,6 +23,7 @@ type ExprContext interface { FuncCount() int DeleteFunc(funcName string) + GetLocalFuncInfo(name string) (info ExprFunc, exists bool) GetFuncInfo(name string) (item ExprFunc, exists bool) Call(name string, args map[string]any) (result any, err error) RegisterFuncInfo(info ExprFunc) diff --git a/expr-function.go b/kern/expr-function.go similarity index 98% rename from expr-function.go rename to kern/expr-function.go index e8545a6..8c639a5 100644 --- a/expr-function.go +++ b/kern/expr-function.go @@ -2,7 +2,7 @@ // All rights reserved. // expr-function.go -package expr +package kern // ---- Functor interface type Functor interface { diff --git a/formatter.go b/kern/formatter.go similarity index 95% rename from formatter.go rename to kern/formatter.go index e188941..67cbfae 100644 --- a/formatter.go +++ b/kern/formatter.go @@ -2,7 +2,7 @@ // All rights reserved. // formatter.go -package expr +package kern import "fmt" @@ -46,7 +46,7 @@ type Formatter interface { ToString(options FmtOpt) string } -func getFormatted(v any, opt FmtOpt) (text string) { +func GetFormatted(v any, opt FmtOpt) (text string) { if v == nil { text = "(nil)" } else if s, ok := v.(string); ok { diff --git a/fraction-type.go b/kern/fraction-type.go similarity index 84% rename from fraction-type.go rename to kern/fraction-type.go index ceec28d..290d402 100644 --- a/fraction-type.go +++ b/kern/fraction-type.go @@ -2,7 +2,7 @@ // All rights reserved. // fraction-type.go -package expr +package kern //https://www.youmath.it/lezioni/algebra-elementare/lezioni-di-algebra-e-aritmetica-per-scuole-medie/553-dalle-frazioni-a-numeri-decimali.html @@ -18,12 +18,12 @@ type FractionType struct { num, den int64 } -func newFraction(num, den int64) *FractionType { +func NewFraction(num, den int64) *FractionType { num, den = simplifyIntegers(num, den) return &FractionType{num, den} } -func float64ToFraction(f float64) (fract *FractionType, err error) { +func Float64ToFraction(f float64) (fract *FractionType, err error) { var sign string intPart, decPart := math.Modf(f) if decPart < 0.0 { @@ -33,11 +33,11 @@ func float64ToFraction(f float64) (fract *FractionType, err error) { } dec := fmt.Sprintf("%.12f", decPart) s := fmt.Sprintf("%s%.f%s", sign, intPart, dec[1:]) - return makeGeneratingFraction(s) + return MakeGeneratingFraction(s) } // Based on https://cs.opensource.google/go/go/+/refs/tags/go1.22.3:src/math/big/rat.go;l=39 -func makeGeneratingFraction(s string) (f *FractionType, err error) { +func MakeGeneratingFraction(s string) (f *FractionType, err error) { var num, den int64 var sign int64 = 1 var parts []string @@ -59,7 +59,7 @@ func makeGeneratingFraction(s string) (f *FractionType, err error) { return } if len(parts) == 1 { - f = newFraction(sign*num, 1) + f = NewFraction(sign*num, 1) } else if len(parts) == 2 { subParts := strings.SplitN(parts[1], "(", 2) if len(subParts) == 1 { @@ -76,7 +76,7 @@ func makeGeneratingFraction(s string) (f *FractionType, err error) { num = num*10 + int64(c-'0') den = den * 10 } - f = newFraction(sign*num, den) + f = NewFraction(sign*num, den) } else if len(subParts) == 2 { sub := num mul := int64(1) @@ -103,7 +103,7 @@ func makeGeneratingFraction(s string) (f *FractionType, err error) { den *= mul } num -= sub - f = newFraction(sign*num, den) + f = NewFraction(sign*num, den) } } exit: @@ -113,7 +113,15 @@ exit: return } -func (f *FractionType) toFloat() float64 { +func (f *FractionType) N() int64 { + return f.num +} + +func (f *FractionType) D() int64 { + return f.den +} + +func (f *FractionType) ToFloat() float64 { return float64(f.num) / float64(f.den) } @@ -168,7 +176,7 @@ func (f *FractionType) TypeName() string { // -------- fraction utility functions // greatest common divider -func gcd(a, b int64) (g int64) { +func Gcd(a, b int64) (g int64) { if a < 0 { a = -a } @@ -189,21 +197,21 @@ func gcd(a, b int64) (g int64) { // lower common multiple func lcm(a, b int64) (l int64) { - g := gcd(a, b) + g := Gcd(a, b) l = a * b / g return } // Sum two fractions -func sumFract(f1, f2 *FractionType) (sum *FractionType) { +func SumFract(f1, f2 *FractionType) (sum *FractionType) { m := lcm(f1.den, f2.den) - sum = newFraction(f1.num*(m/f1.den)+f2.num*(m/f2.den), m) + sum = NewFraction(f1.num*(m/f1.den)+f2.num*(m/f2.den), m) return } // Multiply two fractions -func mulFract(f1, f2 *FractionType) (prod *FractionType) { - prod = newFraction(f1.num*f2.num, f1.den*f2.den) +func MulFract(f1, f2 *FractionType) (prod *FractionType) { + prod = NewFraction(f1.num*f2.num, f1.den*f2.den) return } @@ -230,12 +238,12 @@ func anyPairToFract(v1, v2 any) (f1, f2 *FractionType, err error) { return } -func sumAnyFract(af1, af2 any) (sum any, err error) { +func SumAnyFract(af1, af2 any) (sum any, err error) { var f1, f2 *FractionType if f1, f2, err = anyPairToFract(af1, af2); err != nil { return } - f := sumFract(f1, f2) + f := SumFract(f1, f2) if f.num == 0 { sum = 0 } else { @@ -250,7 +258,7 @@ func sumAnyFract(af1, af2 any) (sum any, err error) { // =0 if af1 == af2 // >0 if af1 > af2 // err if af1 or af2 is not convertible to fraction -func cmpAnyFract(af1, af2 any) (result int, err error) { +func CmpAnyFract(af1, af2 any) (result int, err error) { var f1, f2 *FractionType if f1, f2, err = anyPairToFract(af1, af2); err != nil { return @@ -266,7 +274,7 @@ func cmpAnyFract(af1, af2 any) (result int, err error) { // >0 if af1 > af2 func cmpFract(f1, f2 *FractionType) (result int) { f2.num = -f2.num - f := sumFract(f1, f2) + f := SumFract(f1, f2) if f.num < 0 { result = -1 } else if f.num > 0 { @@ -277,13 +285,13 @@ func cmpFract(f1, f2 *FractionType) (result int) { return } -func subAnyFract(af1, af2 any) (sum any, err error) { +func SubAnyFract(af1, af2 any) (sum any, err error) { var f1, f2 *FractionType if f1, f2, err = anyPairToFract(af1, af2); err != nil { return } f2.num = -f2.num - f := sumFract(f1, f2) + f := SumFract(f1, f2) if f.num == 0 { sum = 0 } else { @@ -292,7 +300,7 @@ func subAnyFract(af1, af2 any) (sum any, err error) { return } -func mulAnyFract(af1, af2 any) (prod any, err error) { +func MulAnyFract(af1, af2 any) (prod any, err error) { var f1, f2 *FractionType if f1, f2, err = anyPairToFract(af1, af2); err != nil { return @@ -306,7 +314,7 @@ func mulAnyFract(af1, af2 any) (prod any, err error) { return } -func divAnyFract(af1, af2 any) (quot any, err error) { +func DivAnyFract(af1, af2 any) (quot any, err error) { var f1, f2 *FractionType if f1, f2, err = anyPairToFract(af1, af2); err != nil { return @@ -345,7 +353,7 @@ func simplifyIntegers(num, den int64) (a, b int64) { den = -den num = -num } - g := gcd(num, den) + g := Gcd(num, den) a = num / g b = den / g return @@ -355,7 +363,7 @@ func intToFraction(n int64) *FractionType { return &FractionType{n, 1} } -func isFraction(v any) (ok bool) { +func IsFraction(v any) (ok bool) { _, ok = v.(*FractionType) return ok } diff --git a/kern/function.go b/kern/function.go new file mode 100644 index 0000000..9cfb948 --- /dev/null +++ b/kern/function.go @@ -0,0 +1,273 @@ +// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// function.go +package kern + +import ( + "fmt" + "strconv" +) + +// ---- Function templates +type FuncTemplate func(ctx ExprContext, name string, args map[string]any) (result any, err error) + +type DeepFuncTemplate func(a, b any) (eq bool, err error) + +// ---- Common functor definition +type BaseFunctor struct { + info ExprFunc +} + +func (functor *BaseFunctor) ToString(opt FmtOpt) (s string) { + if functor.info != nil { + s = functor.info.ToString(opt) + } else { + s = "func(){}" + } + return s +} + +func (functor *BaseFunctor) GetParams() (params []ExprFuncParam) { + if functor.info != nil { + return functor.info.Params() + } else { + return []ExprFuncParam{} + } +} + +func (functor *BaseFunctor) SetFunc(info ExprFunc) { + functor.info = info +} + +func (functor *BaseFunctor) GetFunc() ExprFunc { + return functor.info +} + +func (functor *BaseFunctor) GetDefinitionContext() ExprContext { + return nil +} + +// ---- Function Parameters +type paramFlags uint16 + +const ( + PfDefault paramFlags = 1 << iota + PfOptional + PfRepeat +) + +type funcParamInfo struct { + name string + flags paramFlags + defaultValue any +} + +func NewFuncParam(name string) ExprFuncParam { + return &funcParamInfo{name: name} +} + +func NewFuncParamFlag(name string, flags paramFlags) ExprFuncParam { + return &funcParamInfo{name: name, flags: flags} +} + +func NewFuncParamFlagDef(name string, flags paramFlags, defValue any) *funcParamInfo { + return &funcParamInfo{name: name, flags: flags, defaultValue: defValue} +} + +func (param *funcParamInfo) Name() string { + return param.name +} + +func (param *funcParamInfo) Type() string { + return TypeAny +} + +func (param *funcParamInfo) IsDefault() bool { + return (param.flags & PfDefault) != 0 +} + +func (param *funcParamInfo) IsOptional() bool { + return (param.flags & PfOptional) != 0 +} + +func (param *funcParamInfo) IsRepeat() bool { + return (param.flags & PfRepeat) != 0 +} + +func (param *funcParamInfo) DefaultValue() any { + return param.defaultValue +} + +func initActualParams(ctx ExprContext, info ExprFunc, callTerm Term) (actualParams map[string]any, err error) { + var varArgs []any + var varName string + + namedParamsStarted := false + + formalParams := info.Params() + actualParams = make(map[string]any, len(formalParams)) + if callTerm == nil { + return + } + + childCount := callTerm.GetChildCount() + for i := range childCount { + tree := callTerm.GetChild(i) + // for i, tree := range callTerm.Children() { + var paramValue any + paramCtx := ctx.Clone() + if paramValue, err = tree.Compute(paramCtx); err != nil { + break + } + if paramName, namedParam := GetAssignVarName(tree); namedParam { + if info.ParamSpec(paramName) == nil { + err = fmt.Errorf("%s(): unknown param %q", info.Name(), paramName) + break + } + actualParams[paramName] = paramValue + namedParamsStarted = true + } else if !namedParamsStarted { + if varArgs != nil { + varArgs = append(varArgs, paramValue) + } else if i < len(formalParams) { + spec := formalParams[i] + if spec.IsRepeat() { + varArgs = make([]any, 0, childCount-i) + varArgs = append(varArgs, paramValue) + varName = spec.Name() + } else { + actualParams[spec.Name()] = paramValue + } + } else { + err = ErrTooManyParams(info.Name(), len(formalParams), childCount) + break + } + } else { + err = fmt.Errorf("%s(): positional param nr %d not allowed after named params", info.Name(), i+1) + break + } + } + if err == nil { + if varArgs != nil { + actualParams[varName] = varArgs + } + } + return +} + +// func (info *funcInfo) PrepareCall(name string, actualParams map[string]any) (err error) { +// passedCount := len(actualParams) +// if info.MinArgs() > passedCount { +// err = ErrTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount) +// return +// } + +// if passedCount < len(info.formalParams) { +// for _, p := range info.formalParams { +// if _, exists := actualParams[p.Name()]; !exists { +// if !p.IsDefault() { +// break +// } +// if p.IsRepeat() { +// varArgs := make([]any, 1) +// varArgs[0] = p.DefaultValue() +// actualParams[p.Name()] = varArgs +// } else { +// actualParams[p.Name()] = p.DefaultValue() +// } +// } +// } +// } + +// if info.MaxArgs() >= 0 && info.MaxArgs() < len(actualParams) { +// err = ErrTooManyParams(name, info.MaxArgs(), len(actualParams)) +// } +// return +// } + +// ----- Call a function --- + +// func getAssignVarName(t *term) (name string, ok bool) { +// if ok = t.symbol() == SymEqual; ok { +// name = t.children[0].source() +// } +// return +// } + +func GetAssignVarName(t Term) (name string, ok bool) { + if ok = t.IsAssign(); ok { + name = t.GetChildSource(0) + } + return +} + +func CallFunctionByTerm(parentCtx ExprContext, name string, callTerm Term) (result any, err error) { + var actualParams map[string]any + if info, exists := parentCtx.GetFuncInfo(name); exists { + if actualParams, err = initActualParams(parentCtx, info, callTerm); err == nil { + ctx := info.AllocContext(parentCtx) + if err = info.PrepareCall(name, actualParams); err == nil { + functor := info.Functor() + result, err = functor.InvokeNamed(ctx, name, actualParams) + exportObjectsToParent(ctx) + } + } + } else { + err = fmt.Errorf("unknown function %s()", name) + } + return +} + +func CallFunctionByArgs(parentCtx ExprContext, name string, args []any) (result any, err error) { + var actualParams map[string]any + if info, exists := parentCtx.GetFuncInfo(name); exists { + functor := info.Functor() + actualParams = BindActualParams(functor, args) + ctx := info.AllocContext(parentCtx) + if err = info.PrepareCall(name, actualParams); err == nil { + result, err = functor.InvokeNamed(ctx, name, actualParams) + exportObjectsToParent(ctx) + } + } else { + err = fmt.Errorf("unknown function %s()", name) + } + return +} + +func CallFunctionByParams(parentCtx ExprContext, name string, actualParams map[string]any) (result any, err error) { + //var actualParams map[string]any + if info, exists := parentCtx.GetFuncInfo(name); exists { + functor := info.Functor() + ctx := info.AllocContext(parentCtx) + if err = info.PrepareCall(name, actualParams); err == nil { + result, err = functor.InvokeNamed(ctx, name, actualParams) + exportObjectsToParent(ctx) + } + } else { + err = fmt.Errorf("unknown function %s()", name) + } + return +} + +func GetParam(args map[string]any, paramName string, paramNum int) (value any, exists bool) { + if value, exists = args[paramName]; !exists { + if paramNum > 0 && paramNum <= len(args) { + value, exists = args["arg"+strconv.Itoa(paramNum)] + } + } + return +} + +func BindActualParams(functor Functor, args []any) (actualParams map[string]any) { + formalParams := functor.GetParams() + actualParams = make(map[string]any, len(args)) + for i, arg := range args { + if i < len(formalParams) { + actualParams[formalParams[i].Name()] = arg + } else { + actualParams["arg"+strconv.Itoa(i+1)] = arg + } + } + return +} diff --git a/iterator.go b/kern/iterator.go similarity index 85% rename from iterator.go rename to kern/iterator.go index 2a9e215..207fab1 100644 --- a/iterator.go +++ b/kern/iterator.go @@ -2,7 +2,7 @@ // All rights reserved. // iterator.go -package expr +package kern import ( // "errors" @@ -42,10 +42,6 @@ type ExtIterator interface { Clean() error } -func errNoOperation(name string) error { +func ErrNoOperation(name string) error { return fmt.Errorf("no %s() function defined in the data-source", name) } - -// func errInvalidDataSource() error { -// return errors.New("invalid data-source") -// } diff --git a/list-type.go b/kern/list-type.go similarity index 74% rename from list-type.go rename to kern/list-type.go index b2442c1..eefbf26 100644 --- a/list-type.go +++ b/kern/list-type.go @@ -2,7 +2,7 @@ // All rights reserved. // list-type.go -package expr +package kern import ( "fmt" @@ -12,23 +12,16 @@ import ( type ListType []any -func newListA(listAny ...any) (list *ListType) { +func NewListA(listAny ...any) (list *ListType) { if listAny == nil { listAny = []any{} } - return newList(listAny) -} - -func newList(listAny []any) (list *ListType) { return NewList(listAny) } func NewList(listAny []any) (list *ListType) { if listAny != nil { ls := make(ListType, len(listAny)) - // for i, item := range listAny { - // ls[i] = item - // } copy(ls, listAny) list = &ls } @@ -106,22 +99,11 @@ func (ls *ListType) TypeName() string { return "list" } -// func (list *ListType) indexDeepCmp(target any) (index int) { -// index = -1 -// for i, item := range *list { -// if reflect.DeepEqual(item, target) { -// index = i -// break -// } -// } -// return -// } - -func (ls *ListType) contains(t *ListType) (answer bool) { +func (ls *ListType) Contains(t *ListType) (answer bool) { if len(*ls) >= len(*t) { answer = true for _, item := range *t { - if answer = ls.indexDeepSameCmp(item) >= 0; !answer { + if answer = ls.IndexDeepSameCmp(item) >= 0; !answer { break } } @@ -143,12 +125,12 @@ func (ls1 *ListType) Equals(ls2 ListType) (answer bool) { return } -func (list *ListType) indexDeepSameCmp(target any) (index int) { +func (list *ListType) IndexDeepSameCmp(target any) (index int) { var eq bool var err error index = -1 for i, item := range *list { - if eq, err = deepSame(item, target, sameContent); err != nil { + if eq, err = deepSame(item, target, SameContent); err != nil { break } else if eq { index = i @@ -158,13 +140,13 @@ func (list *ListType) indexDeepSameCmp(target any) (index int) { return } -func sameContent(a, b any) (same bool, err error) { +func SameContent(a, b any) (same bool, err error) { la, _ := a.(*ListType) lb, _ := b.(*ListType) if len(*la) == len(*lb) { same = true for _, item := range *la { - if pos := lb.indexDeepSameCmp(item); pos < 0 { + if pos := lb.IndexDeepSameCmp(item); pos < 0 { same = false break } @@ -173,19 +155,19 @@ func sameContent(a, b any) (same bool, err error) { return } -func deepSame(a, b any, deepCmp deepFuncTemplate) (eq bool, err error) { - if isNumOrFract(a) && isNumOrFract(b) { +func deepSame(a, b any, deepCmp DeepFuncTemplate) (eq bool, err error) { + if IsNumOrFract(a) && IsNumOrFract(b) { if IsNumber(a) && IsNumber(b) { if IsInteger(a) && IsInteger(b) { li, _ := a.(int64) ri, _ := b.(int64) eq = li == ri } else { - eq = numAsFloat(a) == numAsFloat(b) + eq = NumAsFloat(a) == NumAsFloat(b) } } else { var cmp int - if cmp, err = cmpAnyFract(a, b); err == nil { + if cmp, err = CmpAnyFract(a, b); err == nil { eq = cmp == 0 } } @@ -198,7 +180,7 @@ func deepSame(a, b any, deepCmp deepFuncTemplate) (eq bool, err error) { return } -func (list *ListType) setItem(index int64, value any) (err error) { +func (list *ListType) SetItem(index int64, value any) (err error) { if index >= 0 && index < int64(len(*list)) { (*list)[index] = value } else { @@ -207,6 +189,6 @@ func (list *ListType) setItem(index int64, value any) (err error) { return } -func (list *ListType) appendItem(value any) { +func (list *ListType) AppendItem(value any) { *list = append(*list, value) } diff --git a/kern/term.go b/kern/term.go new file mode 100644 index 0000000..d551c95 --- /dev/null +++ b/kern/term.go @@ -0,0 +1,21 @@ +// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// term.go +package kern + +import ( + "fmt" +) + +type Term interface { + fmt.Stringer + // Children() []Term + Source() string + GetChildCount() (count int) + GetChild(index int) Term + GetChildSource(index int) string + Compute(ctx ExprContext) (result any, err error) + IsAssign() bool + Errorf(template string, args ...any) (err error) +} diff --git a/utils-unix.go b/kern/utils-unix.go similarity index 98% rename from utils-unix.go rename to kern/utils-unix.go index c5774db..afd0a35 100644 --- a/utils-unix.go +++ b/kern/utils-unix.go @@ -4,7 +4,7 @@ // All rights reserved. // utils-unix.go -package expr +package kern import ( "os" diff --git a/utils-windows.go b/kern/utils-windows.go similarity index 96% rename from utils-windows.go rename to kern/utils-windows.go index 038b33f..efad62b 100644 --- a/utils-windows.go +++ b/kern/utils-windows.go @@ -4,7 +4,7 @@ // All rights reserved. // utils-unix.go -package expr +package kern import ( "os" diff --git a/utils.go b/kern/utils.go similarity index 87% rename from utils.go rename to kern/utils.go index 1dcc34d..1758bf2 100644 --- a/utils.go +++ b/kern/utils.go @@ -2,7 +2,7 @@ // All rights reserved. // utils.go -package expr +package kern import ( "fmt" @@ -55,29 +55,29 @@ 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 IsNumOrFract(v any) (ok bool) { + return IsFloat(v) || IsInteger(v) || IsFraction(v) } -func isNumberString(v any) (ok bool) { +func IsNumberString(v any) (ok bool) { return IsString(v) || IsNumber(v) } -func isFunctor(v any) (ok bool) { +func IsFunctor(v any) (ok bool) { _, ok = v.(Functor) return } -func isIterator(v any) (ok bool) { +func IsIterator(v any) (ok bool) { _, ok = v.(Iterator) return } -func numAsFloat(v any) (f float64) { +func NumAsFloat(v any) (f float64) { var ok bool if f, ok = v.(float64); !ok { if fract, ok := v.(*FractionType); ok { - f = fract.toFloat() + f = fract.ToFloat() } else { i, _ := v.(int64) f = float64(i) @@ -103,11 +103,11 @@ func ToBool(v any) (b bool, ok bool) { return } -func isFunc(v any) bool { +func IsFunc(v any) bool { return reflect.TypeOf(v).Kind() == reflect.Func } -func anyInteger(v any) (i int64, ok bool) { +func AnyInteger(v any) (i int64, ok bool) { ok = true switch intval := v.(type) { case int: @@ -134,7 +134,7 @@ func anyInteger(v any) (i int64, ok bool) { return } -func fromGenericAny(v any) (exprAny any, ok bool) { +func FromGenericAny(v any) (exprAny any, ok bool) { if v != nil { if exprAny, ok = v.(bool); ok { return @@ -142,10 +142,10 @@ func fromGenericAny(v any) (exprAny any, ok bool) { if exprAny, ok = v.(string); ok { return } - if exprAny, ok = anyInteger(v); ok { + if exprAny, ok = AnyInteger(v); ok { return } - if exprAny, ok = anyFloat(v); ok { + if exprAny, ok = AnyFloat(v); ok { return } if exprAny, ok = v.(*DictType); ok { @@ -158,7 +158,7 @@ func fromGenericAny(v any) (exprAny any, ok bool) { return } -func anyFloat(v any) (float float64, ok bool) { +func AnyFloat(v any) (float float64, ok bool) { ok = true switch floatval := v.(type) { case float32: diff --git a/list-iterator.go b/list-iterator.go index 4c108f9..c30a514 100644 --- a/list-iterator.go +++ b/list-iterator.go @@ -7,10 +7,13 @@ package expr import ( "fmt" "io" + "slices" + + "git.portale-stac.it/go-pkg/expr/kern" ) type ListIterator struct { - a *ListType + a *kern.ListType count int index int start int @@ -18,7 +21,7 @@ type ListIterator struct { step int } -func NewListIterator(list *ListType, args []any) (it *ListIterator) { +func NewListIterator(list *kern.ListType, args []any) (it *ListIterator) { var argc int = 0 listLen := len(([]any)(*list)) if args != nil { @@ -26,21 +29,21 @@ func NewListIterator(list *ListType, args []any) (it *ListIterator) { } it = &ListIterator{a: list, count: 0, index: -1, start: 0, stop: listLen - 1, step: 1} if argc >= 1 { - if i, err := ToGoInt(args[0], "start index"); err == nil { + if i, err := kern.ToGoInt(args[0], "start index"); err == nil { if i < 0 { i = listLen + i } it.start = i } if argc >= 2 { - if i, err := ToGoInt(args[1], "stop index"); err == nil { + if i, err := kern.ToGoInt(args[1], "stop index"); err == nil { if i < 0 { i = listLen + i } it.stop = i } if argc >= 3 { - if i, err := ToGoInt(args[2], "step"); err == nil { + if i, err := kern.ToGoInt(args[2], "step"); err == nil { if i < 0 { i = -i } @@ -58,7 +61,7 @@ func NewListIterator(list *ListType, args []any) (it *ListIterator) { } func NewArrayIterator(array []any) (it *ListIterator) { - it = &ListIterator{a: (*ListType)(&array), count: 0, index: -1, start: 0, stop: len(array) - 1, step: 1} + it = &ListIterator{a: (*kern.ListType)(&array), count: 0, index: -1, start: 0, stop: len(array) - 1, step: 1} return } @@ -75,26 +78,27 @@ func (it *ListIterator) TypeName() string { } func (it *ListIterator) HasOperation(name string) bool { - yes := name == NextName || name == ResetName || name == IndexName || name == CountName || name == CurrentName + //yes := name == expr.NextName || name == expr.ResetName || name == expr.IndexName || name == expr.CountName || name == expr.CurrentName + yes := slices.Contains([]string{kern.NextName, kern.ResetName, kern.IndexName, kern.CountName, kern.CurrentName}, name) return yes } func (it *ListIterator) CallOperation(name string, args map[string]any) (v any, err error) { switch name { - case NextName: + case kern.NextName: v, err = it.Next() - case ResetName: + case kern.ResetName: err = it.Reset() - case CleanName: + case kern.CleanName: err = it.Clean() - case IndexName: + case kern.IndexName: v = int64(it.Index()) - case CurrentName: + case kern.CurrentName: v, err = it.Current() - case CountName: + case kern.CountName: v = it.count default: - err = errNoOperation(name) + err = kern.ErrNoOperation(name) } return } diff --git a/operand-dict.go b/operand-dict.go index 26ba51c..5220892 100644 --- a/operand-dict.go +++ b/operand-dict.go @@ -4,6 +4,9 @@ // operand-dict.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) // -------- dict term func newDictTerm(args map[any]*term) *term { @@ -18,12 +21,12 @@ func newDictTerm(args map[any]*term) *term { } // -------- dict func -func evalDict(ctx ExprContext, opTerm *term) (v any, err error) { +func evalDict(ctx kern.ExprContext, opTerm *term) (v any, err error) { dict, _ := opTerm.value().(map[any]*term) - items := make(DictType, len(dict)) + items := make(kern.DictType, len(dict)) for key, tree := range dict { var param any - if param, err = tree.compute(ctx); err != nil { + if param, err = tree.Compute(ctx); err != nil { break } items[key] = param diff --git a/operand-expr.go b/operand-expr.go index 044a22f..781078c 100644 --- a/operand-expr.go +++ b/operand-expr.go @@ -4,11 +4,15 @@ // operand-expr.go package expr -import "fmt" +import ( + "fmt" + + "git.portale-stac.it/go-pkg/expr/kern" +) // -------- expr term func newExprTerm(root *term) *term { - tk := NewValueToken(root.tk.row, root.tk.col, SymExpression, root.source(), root) + tk := NewValueToken(root.tk.row, root.tk.col, SymExpression, root.Source(), root) return &term{ tk: *tk, parent: nil, @@ -20,9 +24,9 @@ func newExprTerm(root *term) *term { } // -------- eval expr -func evalExpr(ctx ExprContext, opTerm *term) (v any, err error) { - if expr, ok := opTerm.value().(*term); ok { - v, err = expr.compute(ctx) +func evalExpr(ctx kern.ExprContext, opTerm *term) (v any, err error) { + if ast, ok := opTerm.value().(*term); ok { + v, err = ast.Compute(ctx) } else { err = fmt.Errorf("expression expected, got %T", opTerm.value()) } diff --git a/operand-func.go b/operand-func.go index 0b6238a..f16eb39 100644 --- a/operand-func.go +++ b/operand-func.go @@ -6,15 +6,21 @@ package expr import ( "errors" + + "git.portale-stac.it/go-pkg/expr/kern" ) // -------- function call term func newFuncCallTerm(tk *Token, args []*term) *term { + var pos termPosition = posLeaf + if len(args) > 0 { + pos = posMultifix + } return &term{ tk: *tk, parent: nil, children: args, - position: posLeaf, + position: pos, priority: priValue, evalFunc: evalFuncCall, } @@ -38,9 +44,9 @@ func newFuncCallTerm(tk *Token, args []*term) *term { // return // } -func evalFuncCall(ctx ExprContext, opTerm *term) (v any, err error) { +func evalFuncCall(ctx kern.ExprContext, opTerm *term) (v any, err error) { name, _ := opTerm.tk.Value.(string) - v, err = CallFunctionByTerm(ctx, name, opTerm) + v, err = kern.CallFunctionByTerm(ctx, name, opTerm) return } @@ -57,23 +63,23 @@ func newFuncDefTerm(tk *Token, args []*term) *term { } // -------- eval func def -func evalFuncDef(ctx ExprContext, opTerm *term) (v any, err error) { +func evalFuncDef(ctx kern.ExprContext, opTerm *term) (v any, err error) { bodySpec := opTerm.value() - if expr, ok := bodySpec.(*ast); ok { - paramList := make([]ExprFuncParam, 0, len(opTerm.children)) + if ast, ok := bodySpec.(*ast); ok { + paramList := make([]kern.ExprFuncParam, 0, len(opTerm.children)) for _, param := range opTerm.children { var defValue any flags := paramFlags(0) if len(param.children) > 0 { flags |= PfDefault - if defValue, err = param.children[0].compute(ctx); err != nil { + if defValue, err = param.children[0].Compute(ctx); err != nil { return } } - info := NewFuncParamFlagDef(param.source(), flags, defValue) + info := NewFuncParamFlagDef(param.Source(), flags, defValue) paramList = append(paramList, info) } - v = newExprFunctor(expr, paramList, ctx) + v = newExprFunctor(ast, paramList, ctx) } else { err = errors.New("invalid function definition: the body specification must be an expression") } diff --git a/operand-iterator.go b/operand-iterator.go index 6766130..d155a5f 100644 --- a/operand-iterator.go +++ b/operand-iterator.go @@ -7,6 +7,8 @@ package expr import ( "slices" "strings" + + "git.portale-stac.it/go-pkg/expr/kern" ) // -------- iterator term @@ -25,11 +27,11 @@ func newIteratorTerm(tk *Token, args []*term) *term { // -------- eval iterator -func evalTermArray(ctx ExprContext, terms []*term) (values []any, err error) { +func evalTermArray(ctx kern.ExprContext, terms []*term) (values []any, err error) { values = make([]any, len(terms)) for i, t := range terms { var value any - if value, err = t.compute(ctx); err == nil { + if value, err = t.Compute(ctx); err == nil { values[i] = value } else { break @@ -38,25 +40,25 @@ func evalTermArray(ctx ExprContext, terms []*term) (values []any, err error) { return } -func evalFirstChild(ctx ExprContext, iteratorTerm *term) (value any, err error) { +func evalFirstChild(ctx kern.ExprContext, iteratorTerm *term) (value any, err error) { if len(iteratorTerm.children) < 1 || iteratorTerm.children[0] == nil { err = iteratorTerm.Errorf("missing the data-source parameter") return } - value, err = iteratorTerm.children[0].compute(ctx) + value, err = iteratorTerm.children[0].Compute(ctx) return } -func getDataSourceDict(iteratorTerm *term, firstChildValue any) (ds map[string]Functor, err error) { - if dictAny, ok := firstChildValue.(*DictType); ok { - requiredFields := []string{NextName} +func getDataSourceDict(iteratorTerm *term, firstChildValue any) (ds map[string]kern.Functor, err error) { + if dictAny, ok := firstChildValue.(*kern.DictType); ok { + requiredFields := []string{kern.NextName} fieldsMask := 0b1 foundFields := 0 - ds = make(map[string]Functor) + ds = make(map[string]kern.Functor) for keyAny, item := range *dictAny { if key, ok := keyAny.(string); ok { - if functor, ok := item.(Functor); ok { + if functor, ok := item.(kern.Functor); ok { ds[key] = functor if index := slices.Index(requiredFields, key); index >= 0 { foundFields |= 1 << index @@ -78,9 +80,9 @@ func getDataSourceDict(iteratorTerm *term, firstChildValue any) (ds map[string]F return } -func evalIterator(ctx ExprContext, opTerm *term) (v any, err error) { +func evalIterator(ctx kern.ExprContext, opTerm *term) (v any, err error) { var firstChildValue any - var ds map[string]Functor + var ds map[string]kern.Functor if firstChildValue, err = evalFirstChild(ctx, opTerm); err != nil { return @@ -95,7 +97,7 @@ func evalIterator(ctx ExprContext, opTerm *term) (v any, err error) { if len(ds) > 0 { var dc *dataCursor dcCtx := ctx.Clone() - if initFunc, exists := ds[InitName]; exists && initFunc != nil { + if initFunc, exists := ds[kern.InitName]; exists && initFunc != nil { var args []any var resource any if len(opTerm.children) > 1 { @@ -106,13 +108,13 @@ func evalIterator(ctx ExprContext, opTerm *term) (v any, err error) { args = []any{} } - actualParams := bindActualParams(initFunc, args) + actualParams := kern.BindActualParams(initFunc, args) initCtx := ctx.Clone() - if resource, err = initFunc.InvokeNamed(initCtx, InitName, actualParams); err != nil { + if resource, err = initFunc.InvokeNamed(initCtx, kern.InitName, actualParams); err != nil { return } - exportObjects(dcCtx, initCtx) + kern.ExportObjects(dcCtx, initCtx) dc = NewDataCursor(dcCtx, ds, resource) } else { dc = NewDataCursor(dcCtx, ds, nil) @@ -120,7 +122,7 @@ func evalIterator(ctx ExprContext, opTerm *term) (v any, err error) { v = dc } else { - if dictIt, ok := firstChildValue.(*DictType); ok { + if dictIt, ok := firstChildValue.(*kern.DictType); ok { var args []any if args, err = evalSibling(ctx, opTerm.children, nil); err == nil { v, err = NewDictIterator(dictIt, args) @@ -129,7 +131,7 @@ func evalIterator(ctx ExprContext, opTerm *term) (v any, err error) { err = opTerm.children[0].Errorf("the data-source must be a dictionary") } } - } else if list, ok := firstChildValue.(*ListType); ok { + } else if list, ok := firstChildValue.(*kern.ListType); ok { var args []any if args, err = evalSibling(ctx, opTerm.children, nil); err == nil { v = NewListIterator(list, args) @@ -143,7 +145,7 @@ func evalIterator(ctx ExprContext, opTerm *term) (v any, err error) { return } -func evalSibling(ctx ExprContext, terms []*term, firstChildValue any) (list []any, err error) { +func evalSibling(ctx kern.ExprContext, terms []*term, firstChildValue any) (list []any, err error) { items := make([]any, 0, len(terms)) for i, tree := range terms { var param any @@ -152,7 +154,7 @@ func evalSibling(ctx ExprContext, terms []*term, firstChildValue any) (list []an continue } param = firstChildValue - } else if param, err = tree.compute(ctx); err != nil { + } else if param, err = tree.Compute(ctx); err != nil { break } items = append(items, param) diff --git a/operand-list.go b/operand-list.go index ec292cd..173b800 100644 --- a/operand-list.go +++ b/operand-list.go @@ -4,6 +4,10 @@ // operand-list.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + // -------- list term func newListTermA(args ...*term) *term { return newListTerm(0, 0, args) @@ -21,12 +25,12 @@ func newListTerm(row, col int, args []*term) *term { } // -------- list func -func evalList(ctx ExprContext, opTerm *term) (v any, err error) { +func evalList(ctx kern.ExprContext, opTerm *term) (v any, err error) { list, _ := opTerm.value().([]*term) - items := make(ListType, len(list)) + items := make(kern.ListType, len(list)) for i, tree := range list { var param any - if param, err = tree.compute(ctx); err != nil { + if param, err = tree.Compute(ctx); err != nil { break } items[i] = param diff --git a/operand-literal.go b/operand-literal.go index 439ee15..b11cfa4 100644 --- a/operand-literal.go +++ b/operand-literal.go @@ -4,6 +4,10 @@ // operand-literal.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + // -------- literal term func newLiteralTerm(tk *Token) *term { return &term{ @@ -17,7 +21,7 @@ func newLiteralTerm(tk *Token) *term { } // -------- eval func -func evalLiteral(ctx ExprContext, opTerm *term) (v any, err error) { +func evalLiteral(ctx kern.ExprContext, opTerm *term) (v any, err error) { v = opTerm.tk.Value return } diff --git a/operand-selector-case.go b/operand-selector-case.go index 7b48604..af61dad 100644 --- a/operand-selector-case.go +++ b/operand-selector-case.go @@ -7,6 +7,8 @@ package expr import ( "fmt" "strings" + + "git.portale-stac.it/go-pkg/expr/kern" ) // -------- selector case term @@ -41,7 +43,7 @@ func newSelectorCaseTerm(row, col int, filterList *term, caseExpr Expr) *term { } // -------- eval selector case -func evalSelectorCase(ctx ExprContext, opTerm *term) (v any, err error) { +func evalSelectorCase(ctx kern.ExprContext, opTerm *term) (v any, err error) { var ok bool if v, ok = opTerm.value().(*selectorCase); !ok { err = fmt.Errorf("selector-case expected, got %T", opTerm.value()) diff --git a/operand-var.go b/operand-var.go index 590ab53..d66d94c 100644 --- a/operand-var.go +++ b/operand-var.go @@ -4,7 +4,11 @@ // operand-var.go package expr -import "fmt" +import ( + "fmt" + + "git.portale-stac.it/go-pkg/expr/kern" +) // -------- variable term func newVarTerm(tk *Token) *term { @@ -21,11 +25,11 @@ func newVarTerm(tk *Token) *term { } // -------- eval func -func evalVar(ctx ExprContext, opTerm *term) (v any, err error) { +func evalVar(ctx kern.ExprContext, opTerm *term) (v any, err error) { var exists bool - name := opTerm.source() - if v, exists = GetVar(ctx, name); !exists { - if info, exists := GetFuncInfo(ctx, name); exists { + name := opTerm.Source() + if v, exists = ctx.GetVar(name); !exists { + if info, exists := ctx.GetFuncInfo(name); exists { v = info.Functor() } else { err = fmt.Errorf("undefined variable or function %q", name) diff --git a/operator-assign.go b/operator-assign.go index 9ea97b4..5dcdb4a 100644 --- a/operator-assign.go +++ b/operator-assign.go @@ -4,6 +4,10 @@ // operator-assign.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + //-------- assign term func newAssignTerm(tk *Token) (inst *term) { @@ -16,19 +20,19 @@ func newAssignTerm(tk *Token) (inst *term) { } } -func assignCollectionItem(ctx ExprContext, collectionTerm, keyListTerm *term, value any) (err error) { +func assignCollectionItem(ctx kern.ExprContext, collectionTerm, keyListTerm *term, value any) (err error) { var collectionValue, keyListValue, keyValue any - var keyList *ListType + var keyList *kern.ListType var ok bool - if collectionValue, err = collectionTerm.compute(ctx); err != nil { + if collectionValue, err = collectionTerm.Compute(ctx); err != nil { return } - if keyListValue, err = keyListTerm.compute(ctx); err != nil { + if keyListValue, err = keyListTerm.Compute(ctx); err != nil { return - } else if keyList, ok = keyListValue.(*ListType); !ok || len(*keyList) != 1 { - err = keyListTerm.Errorf("index/key specification expected, got %v [%s]", keyListValue, TypeName(keyListValue)) + } else if keyList, ok = keyListValue.(*kern.ListType); !ok || len(*keyList) != 1 { + err = keyListTerm.Errorf("index/key specification expected, got %v [%s]", keyListValue, kern.TypeName(keyListValue)) return } if keyValue = (*keyList)[0]; keyValue == nil { @@ -37,30 +41,30 @@ func assignCollectionItem(ctx ExprContext, collectionTerm, keyListTerm *term, va } switch collection := collectionValue.(type) { - case *ListType: + case *kern.ListType: if index, ok := keyValue.(int64); ok { - err = collection.setItem(index, value) + err = collection.SetItem(index, value) } else { - err = keyListTerm.Errorf("integer expected, got %v [%s]", keyValue, TypeName(keyValue)) + err = keyListTerm.Errorf("integer expected, got %v [%s]", keyValue, kern.TypeName(keyValue)) } - case *DictType: - err = collection.setItem(keyValue, value) + case *kern.DictType: + err = collection.SetItem(keyValue, value) default: err = collectionTerm.Errorf("collection expected") } return } -func assignValue(ctx ExprContext, leftTerm *term, v any) (err error) { +func assignValue(ctx kern.ExprContext, leftTerm *term, v any) (err error) { if leftTerm.symbol() == SymIndex { err = assignCollectionItem(ctx, leftTerm.children[0], leftTerm.children[1], v) } else { - ctx.UnsafeSetVar(leftTerm.source(), v) + ctx.UnsafeSetVar(leftTerm.Source(), v) } return } -func evalAssign(ctx ExprContext, opTerm *term) (v any, err error) { +func evalAssign(ctx kern.ExprContext, opTerm *term) (v any, err error) { if err = opTerm.checkOperands(); err != nil { return } @@ -74,17 +78,17 @@ func evalAssign(ctx ExprContext, opTerm *term) (v any, err error) { rightChild := opTerm.children[1] - if v, err = rightChild.compute(ctx); err == nil { - if functor, ok := v.(Functor); ok { + if v, err = rightChild.Compute(ctx); err == nil { + if functor, ok := v.(kern.Functor); ok { if leftSym == SymVariable { if info := functor.GetFunc(); info != nil { - ctx.RegisterFunc(leftTerm.source(), info.Functor(), info.ReturnType(), info.Params()) + ctx.RegisterFunc(leftTerm.Source(), info.Functor(), info.ReturnType(), info.Params()) } else if funcDef, ok := functor.(*exprFunctor); ok { - paramSpecs := ForAll(funcDef.params, func(p ExprFuncParam) ExprFuncParam { return p }) + paramSpecs := kern.ForAll(funcDef.params, func(p kern.ExprFuncParam) kern.ExprFuncParam { return p }) - ctx.RegisterFunc(leftTerm.source(), functor, TypeAny, paramSpecs) + ctx.RegisterFunc(leftTerm.Source(), functor, kern.TypeAny, paramSpecs) } else { - err = opTerm.Errorf("unknown function %s()", rightChild.source()) + err = opTerm.Errorf("unknown function %s()", rightChild.Source()) } } else { err = assignValue(ctx, leftTerm, v) @@ -111,19 +115,19 @@ func newOpAssignTerm(tk *Token) (inst *term) { } } -func getCollectionItemValue(ctx ExprContext, collectionTerm, keyListTerm *term) (value any, err error) { +func getCollectionItemValue(ctx kern.ExprContext, collectionTerm, keyListTerm *term) (value any, err error) { var collectionValue, keyListValue, keyValue any - var keyList *ListType + var keyList *kern.ListType var ok bool - if collectionValue, err = collectionTerm.compute(ctx); err != nil { + if collectionValue, err = collectionTerm.Compute(ctx); err != nil { return } - if keyListValue, err = keyListTerm.compute(ctx); err != nil { + if keyListValue, err = keyListTerm.Compute(ctx); err != nil { return - } else if keyList, ok = keyListValue.(*ListType); !ok || len(*keyList) != 1 { - err = keyListTerm.Errorf("index/key specification expected, got %v [%s]", keyListValue, TypeName(keyListValue)) + } else if keyList, ok = keyListValue.(*kern.ListType); !ok || len(*keyList) != 1 { + err = keyListTerm.Errorf("index/key specification expected, got %v [%s]", keyListValue, kern.TypeName(keyListValue)) return } if keyValue = (*keyList)[0]; keyValue == nil { @@ -132,13 +136,13 @@ func getCollectionItemValue(ctx ExprContext, collectionTerm, keyListTerm *term) } switch collection := collectionValue.(type) { - case *ListType: + case *kern.ListType: if index, ok := keyValue.(int64); ok { value = (*collection)[index] } else { - err = keyListTerm.Errorf("integer expected, got %v [%s]", keyValue, TypeName(keyValue)) + err = keyListTerm.Errorf("integer expected, got %v [%s]", keyValue, kern.TypeName(keyValue)) } - case *DictType: + case *kern.DictType: value = (*collection)[keyValue] default: err = collectionTerm.Errorf("collection expected") @@ -146,16 +150,16 @@ func getCollectionItemValue(ctx ExprContext, collectionTerm, keyListTerm *term) return } -func getAssignValue(ctx ExprContext, leftTerm *term) (value any, err error) { +func getAssignValue(ctx kern.ExprContext, leftTerm *term) (value any, err error) { if leftTerm.symbol() == SymIndex { value, err = getCollectionItemValue(ctx, leftTerm.children[0], leftTerm.children[1]) } else { - value, _ = ctx.GetVar(leftTerm.source()) + value, _ = ctx.GetVar(leftTerm.Source()) } return } -func evalOpAssign(ctx ExprContext, opTerm *term) (v any, err error) { +func evalOpAssign(ctx kern.ExprContext, opTerm *term) (v any, err error) { var rightValue, leftValue any if err = opTerm.checkOperands(); err != nil { return @@ -170,7 +174,7 @@ func evalOpAssign(ctx ExprContext, opTerm *term) (v any, err error) { rightChild := opTerm.children[1] - if rightValue, err = rightChild.compute(ctx); err == nil { + if rightValue, err = rightChild.Compute(ctx); err == nil { if leftValue, err = getAssignValue(ctx, leftTerm); err == nil { switch opTerm.symbol() { case SymPlusEqual: @@ -194,7 +198,7 @@ func evalOpAssign(ctx ExprContext, opTerm *term) (v any, err error) { case SymDoubleGreaterEqual: v, err = bitRightShift(opTerm, leftValue, rightValue) default: - err = opTerm.Errorf("unsupported assign operator %q", opTerm.source()) + err = opTerm.Errorf("unsupported assign operator %q", opTerm.Source()) } if err == nil { err = assignValue(ctx, leftTerm, v) diff --git a/operator-bitwise.go b/operator-bitwise.go index 6815025..a6bf828 100644 --- a/operator-bitwise.go +++ b/operator-bitwise.go @@ -4,6 +4,10 @@ // operator-bitwise.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + //-------- Bitwise NOT term func newBitwiseNotTerm(tk *Token) (inst *term) { @@ -16,18 +20,18 @@ func newBitwiseNotTerm(tk *Token) (inst *term) { } } -func evalBitwiseNot(ctx ExprContext, opTerm *term) (v any, err error) { +func evalBitwiseNot(ctx kern.ExprContext, opTerm *term) (v any, err error) { var value any if value, err = opTerm.evalPrefix(ctx); err != nil { return } - if IsInteger(value) { + if kern.IsInteger(value) { i, _ := value.(int64) v = ^i } else { - err = opTerm.errIncompatibleType(value) + err = opTerm.errIncompatiblePrefixPostfixType(value) } return } @@ -59,7 +63,7 @@ func bitwiseAnd(opTerm *term, leftValue, rightValue any) (v any, err error) { return } -func evalBitwiseAnd(ctx ExprContext, opTerm *term) (v any, err error) { +func evalBitwiseAnd(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil { @@ -96,7 +100,7 @@ func bitwiseOr(opTerm *term, leftValue, rightValue any) (v any, err error) { return } -func evalBitwiseOr(ctx ExprContext, opTerm *term) (v any, err error) { +func evalBitwiseOr(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil { @@ -134,7 +138,7 @@ func bitwiseXor(opTerm *term, leftValue, rightValue any) (v any, err error) { return } -func evalBitwiseXor(ctx ExprContext, opTerm *term) (v any, err error) { +func evalBitwiseXor(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil { diff --git a/operator-bool.go b/operator-bool.go index c32dfc4..7a116bc 100644 --- a/operator-bool.go +++ b/operator-bool.go @@ -4,7 +4,11 @@ // operator-bool.go package expr -import "fmt" +import ( + "fmt" + + "git.portale-stac.it/go-pkg/expr/kern" +) //-------- NOT term @@ -18,17 +22,17 @@ func newNotTerm(tk *Token) (inst *term) { } } -func evalNot(ctx ExprContext, opTerm *term) (v any, err error) { +func evalNot(ctx kern.ExprContext, opTerm *term) (v any, err error) { var rightValue any if rightValue, err = opTerm.evalPrefix(ctx); err != nil { return } - if b, ok := ToBool(rightValue); ok { + if b, ok := kern.ToBool(rightValue); ok { v = !b } else { - err = opTerm.errIncompatibleType(rightValue) + err = opTerm.errIncompatiblePrefixPostfixType(rightValue) } return } @@ -45,8 +49,8 @@ func newAndTerm(tk *Token) (inst *term) { } } -func evalAnd(ctx ExprContext, self *term) (v any, err error) { - if CtrlIsEnabled(ctx, ControlBoolShortcut) { +func evalAnd(ctx kern.ExprContext, self *term) (v any, err error) { + if kern.CtrlIsEnabled(ctx, kern.ControlBoolShortcut) { v, err = evalAndWithShortcut(ctx, self) } else { v, err = evalAndWithoutShortcut(ctx, self) @@ -54,7 +58,7 @@ func evalAnd(ctx ExprContext, self *term) (v any, err error) { return } -func evalAndWithoutShortcut(ctx ExprContext, self *term) (v any, err error) { +func evalAndWithoutShortcut(ctx kern.ExprContext, self *term) (v any, err error) { var leftValue, rightValue any var leftBool, rightBool bool var lok, rok bool @@ -63,8 +67,8 @@ func evalAndWithoutShortcut(ctx ExprContext, self *term) (v any, err error) { return } - leftBool, lok = ToBool(leftValue) - rightBool, rok = ToBool(rightValue) + leftBool, lok = kern.ToBool(leftValue) + rightBool, rok = kern.ToBool(rightValue) if lok && rok { v = leftBool && rightBool @@ -74,24 +78,25 @@ func evalAndWithoutShortcut(ctx ExprContext, self *term) (v any, err error) { return } -func evalAndWithShortcut(ctx ExprContext, self *term) (v any, err error) { +func evalAndWithShortcut(ctx kern.ExprContext, self *term) (v any, err error) { var leftValue, rightValue any if err = self.checkOperands(); err != nil { return } - if leftValue, err = self.children[0].compute(ctx); err != nil { + if leftValue, err = self.children[0].Compute(ctx); err != nil { return } - if leftBool, lok := ToBool(leftValue); !lok { - err = fmt.Errorf("got %s as left operand type of 'AND' operator, it must be bool", TypeName(leftValue)) - return + if leftBool, lok := kern.ToBool(leftValue); !lok { + // err = fmt.Errorf("got %s as left operand type of 'AND' operator, it must be bool", expr.TypeName(leftValue)) + // return + err = self.errIncompatibleType(leftValue, "left") } else if !leftBool { v = false - } else if rightValue, err = self.children[1].compute(ctx); err == nil { - if rightBool, rok := ToBool(rightValue); rok { + } else if rightValue, err = self.children[1].Compute(ctx); err == nil { + if rightBool, rok := kern.ToBool(rightValue); rok { v = rightBool } else { err = self.errIncompatibleTypes(leftValue, rightValue) @@ -112,8 +117,8 @@ func newOrTerm(tk *Token) (inst *term) { } } -func evalOr(ctx ExprContext, self *term) (v any, err error) { - if CtrlIsEnabled(ctx, ControlBoolShortcut) { +func evalOr(ctx kern.ExprContext, self *term) (v any, err error) { + if kern.CtrlIsEnabled(ctx, kern.ControlBoolShortcut) { v, err = evalOrWithShortcut(ctx, self) } else { v, err = evalOrWithoutShortcut(ctx, self) @@ -121,7 +126,7 @@ func evalOr(ctx ExprContext, self *term) (v any, err error) { return } -func evalOrWithoutShortcut(ctx ExprContext, self *term) (v any, err error) { +func evalOrWithoutShortcut(ctx kern.ExprContext, self *term) (v any, err error) { var leftValue, rightValue any var leftBool, rightBool bool var lok, rok bool @@ -130,8 +135,8 @@ func evalOrWithoutShortcut(ctx ExprContext, self *term) (v any, err error) { return } - leftBool, lok = ToBool(leftValue) - rightBool, rok = ToBool(rightValue) + leftBool, lok = kern.ToBool(leftValue) + rightBool, rok = kern.ToBool(rightValue) if lok && rok { v = leftBool || rightBool @@ -141,24 +146,24 @@ func evalOrWithoutShortcut(ctx ExprContext, self *term) (v any, err error) { return } -func evalOrWithShortcut(ctx ExprContext, self *term) (v any, err error) { +func evalOrWithShortcut(ctx kern.ExprContext, self *term) (v any, err error) { var leftValue, rightValue any if err = self.checkOperands(); err != nil { return } - if leftValue, err = self.children[0].compute(ctx); err != nil { + if leftValue, err = self.children[0].Compute(ctx); err != nil { return } - if leftBool, lok := ToBool(leftValue); !lok { - err = fmt.Errorf("got %s as left operand type of 'OR' operator, it must be bool", TypeName(leftValue)) + if leftBool, lok := kern.ToBool(leftValue); !lok { + err = fmt.Errorf("got %s as left operand type of 'OR' operator, it must be bool", kern.TypeName(leftValue)) return } else if leftBool { v = true - } else if rightValue, err = self.children[1].compute(ctx); err == nil { - if rightBool, rok := ToBool(rightValue); rok { + } else if rightValue, err = self.children[1].Compute(ctx); err == nil { + if rightBool, rok := kern.ToBool(rightValue); rok { v = rightBool } else { err = self.errIncompatibleTypes(leftValue, rightValue) diff --git a/operator-builtin.go b/operator-builtin.go index 38044e7..44631c8 100644 --- a/operator-builtin.go +++ b/operator-builtin.go @@ -4,7 +4,11 @@ // operator-builtin.go package expr -import "io" +import ( + "io" + + "git.portale-stac.it/go-pkg/expr/kern" +) //-------- builtin term @@ -18,7 +22,7 @@ func newBuiltinTerm(tk *Token) (inst *term) { } } -func evalBuiltin(ctx ExprContext, opTerm *term) (v any, err error) { +func evalBuiltin(ctx kern.ExprContext, opTerm *term) (v any, err error) { var childValue any if childValue, err = opTerm.evalPrefix(ctx); err != nil { @@ -26,25 +30,25 @@ func evalBuiltin(ctx ExprContext, opTerm *term) (v any, err error) { } count := 0 - if IsString(childValue) { + if kern.IsString(childValue) { module, _ := childValue.(string) - count, err = ImportInContextByGlobPattern(module) + count, err = ImportInContextByGlobPattern(ctx, module) } else { var moduleSpec any - var it Iterator + var it kern.Iterator if it, err = NewIterator(childValue); err != nil { return } for moduleSpec, err = it.Next(); err == nil; moduleSpec, err = it.Next() { if module, ok := moduleSpec.(string); ok { - if ImportInContext(module) { + if ImportInContext(ctx, module) { count++ } else { err = opTerm.Errorf("unknown builtin module %q", module) break } } else { - err = opTerm.Errorf("expected string at item nr %d, got %s", it.Index()+1, TypeName(moduleSpec)) + err = opTerm.Errorf("expected string at item nr %d, got %s", it.Index()+1, kern.TypeName(moduleSpec)) break } } diff --git a/operator-but.go b/operator-but.go index 0b1044c..92daf86 100644 --- a/operator-but.go +++ b/operator-but.go @@ -4,6 +4,10 @@ // operator-but.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + //-------- but term func newButTerm(tk *Token) (inst *term) { @@ -16,7 +20,7 @@ func newButTerm(tk *Token) (inst *term) { } } -func evalBut(ctx ExprContext, opTerm *term) (v any, err error) { +func evalBut(ctx kern.ExprContext, opTerm *term) (v any, err error) { _, v, err = opTerm.evalInfix(ctx) return } diff --git a/operator-context.go b/operator-context.go index 1a2c76d..c4d5df8 100644 --- a/operator-context.go +++ b/operator-context.go @@ -4,6 +4,10 @@ // operator-context-value.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + //-------- context term func newContextTerm(tk *Token) (inst *term) { @@ -16,14 +20,14 @@ func newContextTerm(tk *Token) (inst *term) { } } -func evalContextValue(ctx ExprContext, opTerm *term) (v any, err error) { +func evalContextValue(ctx kern.ExprContext, opTerm *term) (v any, err error) { var childValue any - var sourceCtx ExprContext + var sourceCtx kern.ExprContext if len(opTerm.children) == 0 { sourceCtx = ctx - } else if opTerm.children[0].symbol() == SymVariable && opTerm.children[0].source() == "global" { - sourceCtx = globalCtx + } else if opTerm.children[0].symbol() == SymVariable && opTerm.children[0].Source() == "global" { + sourceCtx = ctx.GetGlobal() } else if childValue, err = opTerm.evalPrefix(ctx); err == nil { if dc, ok := childValue.(*dataCursor); ok { sourceCtx = dc.ctx @@ -31,9 +35,9 @@ func evalContextValue(ctx ExprContext, opTerm *term) (v any, err error) { } if sourceCtx != nil { - if formatter, ok := sourceCtx.(DictFormat); ok { + if formatter, ok := sourceCtx.(kern.DictFormat); ok { v = formatter.ToDict() - } else if formatter, ok := sourceCtx.(Formatter); ok { + } else if formatter, ok := sourceCtx.(kern.Formatter); ok { v = formatter.ToString(0) } else { // keys := sourceCtx.EnumVars(func(name string) bool { return name[0] != '_' }) @@ -49,7 +53,7 @@ func evalContextValue(ctx ExprContext, opTerm *term) (v any, err error) { v = d } } else { - err = opTerm.errIncompatibleType(childValue) + err = opTerm.errIncompatiblePrefixPostfixType(childValue) } return } diff --git a/operator-ctrl.go b/operator-ctrl.go index 50b5f47..04ce944 100644 --- a/operator-ctrl.go +++ b/operator-ctrl.go @@ -4,6 +4,10 @@ // operator-ctrl.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + //-------- export all term func newExportAllTerm(tk *Token) (inst *term) { @@ -16,8 +20,8 @@ func newExportAllTerm(tk *Token) (inst *term) { } } -func evalExportAll(ctx ExprContext, opTerm *term) (v any, err error) { - CtrlEnable(ctx, control_export_all) +func evalExportAll(ctx kern.ExprContext, opTerm *term) (v any, err error) { + CtrlEnable(ctx, kern.ControlExportAll) return } diff --git a/operator-default.go b/operator-default.go index 607eda3..730a4fa 100644 --- a/operator-default.go +++ b/operator-default.go @@ -4,6 +4,10 @@ // operator-default.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + //-------- default term func newDefaultTerm(tk *Token) (inst *term) { @@ -16,7 +20,7 @@ func newDefaultTerm(tk *Token) (inst *term) { } } -func evalDefault(ctx ExprContext, opTerm *term) (v any, err error) { +func evalDefault(ctx kern.ExprContext, opTerm *term) (v any, err error) { var rightValue any if err = opTerm.checkOperands(); err != nil { @@ -26,13 +30,13 @@ func evalDefault(ctx ExprContext, opTerm *term) (v any, err error) { leftTerm := opTerm.children[0] if leftTerm.tk.Sym != SymVariable { // err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source) - err = ErrLeftOperandMustBeVariable(leftTerm, opTerm) + err = kern.ErrLeftOperandMustBeVariable(leftTerm, opTerm) return } - if leftValue, exists := ctx.GetVar(leftTerm.source()); exists { + if leftValue, exists := ctx.GetVar(leftTerm.Source()); exists { v = leftValue - } else if rightValue, err = opTerm.children[1].compute(ctx); err == nil { + } else if rightValue, err = opTerm.children[1].Compute(ctx); err == nil { v = rightValue } return @@ -50,7 +54,7 @@ func newAlternateTerm(tk *Token) (inst *term) { } } -func evalAlternate(ctx ExprContext, opTerm *term) (v any, err error) { +func evalAlternate(ctx kern.ExprContext, opTerm *term) (v any, err error) { var rightValue any if err = opTerm.checkOperands(); err != nil { @@ -60,12 +64,12 @@ func evalAlternate(ctx ExprContext, opTerm *term) (v any, err error) { leftTerm := opTerm.children[0] if leftTerm.tk.Sym != SymVariable { // err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source) - err = ErrLeftOperandMustBeVariable(leftTerm, opTerm) + err = kern.ErrLeftOperandMustBeVariable(leftTerm, opTerm) return } - if leftValue, exists := ctx.GetVar(leftTerm.source()); exists && leftValue != nil { - if rightValue, err = opTerm.children[1].compute(ctx); err == nil { + if leftValue, exists := ctx.GetVar(leftTerm.Source()); exists && leftValue != nil { + if rightValue, err = opTerm.children[1].Compute(ctx); err == nil { v = rightValue } } else { @@ -86,7 +90,7 @@ func newDefaultAssignTerm(tk *Token) (inst *term) { } } -func evalAssignDefault(ctx ExprContext, opTerm *term) (v any, err error) { +func evalAssignDefault(ctx kern.ExprContext, opTerm *term) (v any, err error) { var rightValue any if err = opTerm.checkOperands(); err != nil { @@ -96,21 +100,21 @@ func evalAssignDefault(ctx ExprContext, opTerm *term) (v any, err error) { leftTerm := opTerm.children[0] if leftTerm.tk.Sym != SymVariable { // err = leftTerm.Errorf("left operand of %q must be a variable", self.tk.source) - err = ErrLeftOperandMustBeVariable(leftTerm, opTerm) + err = kern.ErrLeftOperandMustBeVariable(leftTerm, opTerm) return } - if leftValue, exists := ctx.GetVar(leftTerm.source()); exists { + if leftValue, exists := ctx.GetVar(leftTerm.Source()); exists { v = leftValue - } else if rightValue, err = opTerm.children[1].compute(ctx); err == nil { - if functor, ok := rightValue.(Functor); ok { + } else if rightValue, err = opTerm.children[1].Compute(ctx); err == nil { + if functor, ok := rightValue.(kern.Functor); ok { //ctx.RegisterFunc(leftTerm.source(), functor, 0, -1) - ctx.RegisterFunc(leftTerm.source(), functor, TypeAny, []ExprFuncParam{ - NewFuncParamFlag(ParamValue, PfDefault|PfRepeat), + ctx.RegisterFunc(leftTerm.Source(), functor, kern.TypeAny, []kern.ExprFuncParam{ + NewFuncParamFlag(kern.ParamValue, PfDefault|PfRepeat), }) } else { v = rightValue - ctx.UnsafeSetVar(leftTerm.source(), rightValue) + ctx.UnsafeSetVar(leftTerm.Source(), rightValue) } } return diff --git a/operator-digest.go b/operator-digest.go index a52e953..632e26f 100644 --- a/operator-digest.go +++ b/operator-digest.go @@ -7,6 +7,8 @@ package expr import ( "fmt" "io" + + "git.portale-stac.it/go-pkg/expr/kern" ) //-------- digest term @@ -21,21 +23,21 @@ func newDigestTerm(tk *Token) (inst *term) { } } -func evalDigest(ctx ExprContext, opTerm *term) (v any, err error) { +func evalDigest(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any - var it Iterator + var it kern.Iterator var item, lastValue any if err = opTerm.checkOperands(); err != nil { return } - if leftValue, err = opTerm.children[0].compute(ctx); err != nil { + if leftValue, err = opTerm.children[0].Compute(ctx); err != nil { return } if it, err = NewIterator(leftValue); err != nil { - return nil, fmt.Errorf("left operand of DIGEST must be an iterable data-source; got %s", TypeName(leftValue)) + return nil, fmt.Errorf("left operand of DIGEST must be an iterable data-source; got %s", kern.TypeName(leftValue)) } lastValue = nil @@ -43,7 +45,7 @@ func evalDigest(ctx ExprContext, opTerm *term) (v any, err error) { ctx.SetVar("_", item) ctx.SetVar("_index", it.Index()) ctx.SetVar("_count", it.Count()) - if rightValue, err = opTerm.children[1].compute(ctx); err == nil { + if rightValue, err = opTerm.children[1].Compute(ctx); err == nil { if rightValue == nil { break } else { diff --git a/operator-dot.go b/operator-dot.go index e097438..2d99755 100644 --- a/operator-dot.go +++ b/operator-dot.go @@ -4,6 +4,10 @@ // operator-dot.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + // -------- dot term func newDotTerm(tk *Token) (inst *term) { return &term{ @@ -15,22 +19,22 @@ func newDotTerm(tk *Token) (inst *term) { } } -func evalDot(ctx ExprContext, opTerm *term) (v any, err error) { +func evalDot(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any if err = opTerm.checkOperands(); err != nil { return } - if leftValue, err = opTerm.children[0].compute(ctx); err != nil { + if leftValue, err = opTerm.children[0].Compute(ctx); err != nil { return } indexTerm := opTerm.children[1] switch unboxedValue := leftValue.(type) { - case ExtIterator: + case kern.ExtIterator: if indexTerm.symbol() == SymVariable /*|| indexTerm.symbol() == SymString */ { - opName := indexTerm.source() + opName := indexTerm.Source() if unboxedValue.HasOperation(opName) { v, err = unboxedValue.CallOperation(opName, map[string]any{}) } else { @@ -41,7 +45,7 @@ func evalDot(ctx ExprContext, opTerm *term) (v any, err error) { err = indexTerm.tk.ErrorExpectedGot("identifier") } default: - if rightValue, err = opTerm.children[1].compute(ctx); err == nil { + if rightValue, err = opTerm.children[1].Compute(ctx); err == nil { err = opTerm.errIncompatibleTypes(leftValue, rightValue) } } diff --git a/operator-fact.go b/operator-fact.go index d38215f..1d37603 100644 --- a/operator-fact.go +++ b/operator-fact.go @@ -4,7 +4,11 @@ // operator-fact.go package expr -import "fmt" +import ( + "fmt" + + "git.portale-stac.it/go-pkg/expr/kern" +) //-------- fact term @@ -18,14 +22,14 @@ func newFactTerm(tk *Token) (inst *term) { } } -func evalFact(ctx ExprContext, opTerm *term) (v any, err error) { +func evalFact(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue any if leftValue, err = opTerm.evalPrefix(ctx); err != nil { return } - if IsInteger(leftValue) { + if kern.IsInteger(leftValue) { if i, _ := leftValue.(int64); i >= 0 { f := int64(1) for k := int64(1); k <= i; k++ { @@ -36,7 +40,7 @@ func evalFact(ctx ExprContext, opTerm *term) (v any, err error) { err = fmt.Errorf("factorial of a negative integer (%d) is not allowed", i) } } else { - err = opTerm.errIncompatibleType(leftValue) + err = opTerm.errIncompatiblePrefixPostfixType(leftValue) } return } diff --git a/operator-filter.go b/operator-filter.go index 8943080..b8652c0 100644 --- a/operator-filter.go +++ b/operator-filter.go @@ -7,6 +7,8 @@ package expr import ( "fmt" "io" + + "git.portale-stac.it/go-pkg/expr/kern" ) //-------- map term @@ -21,32 +23,32 @@ func newFilterTerm(tk *Token) (inst *term) { } } -func evalFilter(ctx ExprContext, opTerm *term) (v any, err error) { +func evalFilter(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any - var it Iterator + var it kern.Iterator var item any if err = opTerm.checkOperands(); err != nil { return } - if leftValue, err = opTerm.children[0].compute(ctx); err != nil { + if leftValue, err = opTerm.children[0].Compute(ctx); err != nil { return } if it, err = NewIterator(leftValue); err != nil { - return nil, fmt.Errorf("left operand of FILTER must be an iterable data-source; got %s", TypeName(leftValue)) + return nil, fmt.Errorf("left operand of FILTER must be an iterable data-source; got %s", kern.TypeName(leftValue)) } - values := newListA() + values := kern.NewListA() for item, err = it.Next(); err == nil; item, err = it.Next() { ctx.SetVar("_", item) ctx.SetVar("_index", it.Index()) ctx.SetVar("_count", it.Count()) - if rightValue, err = opTerm.children[1].compute(ctx); err == nil { - if success, valid := ToBool(rightValue); valid { + if rightValue, err = opTerm.children[1].Compute(ctx); err == nil { + if success, valid := kern.ToBool(rightValue); valid { if success { - values.appendItem(item) + values.AppendItem(item) } } else { err = fmt.Errorf("filter expression must return a boolean or a castable to boolean, got %v [%T]", rightValue, rightValue) diff --git a/operator-fraction.go b/operator-fraction.go index 9f6f13b..9fc3e09 100644 --- a/operator-fraction.go +++ b/operator-fraction.go @@ -8,6 +8,8 @@ package expr import ( "fmt" + + "git.portale-stac.it/go-pkg/expr/kern" ) // -------- fraction term @@ -23,7 +25,7 @@ func newFractionTerm(tk *Token) *term { } // -------- eval func -func evalFraction(ctx ExprContext, opTerm *term) (v any, err error) { +func evalFraction(ctx kern.ExprContext, opTerm *term) (v any, err error) { var numValue, denValue any var num, den int64 var ok bool @@ -49,16 +51,19 @@ func evalFraction(ctx ExprContext, opTerm *term) (v any, err error) { num = -num } if num != 0 { - g := gcd(num, den) - num = num / g - den = den / g + if g := kern.Gcd(num, den); g != 1 { + num = num / g + den = den / g + } if den == 1 { v = num } else { - v = &FractionType{num, den} + // v = &expr.FractionType{num, den} + v = kern.NewFraction(num, den) } } else { - v = &FractionType{0, den} + // v = &FractionType{0, den} + v = kern.NewFraction(0, den) } return } diff --git a/operator-in.go b/operator-in.go index 8300426..cfb2cff 100644 --- a/operator-in.go +++ b/operator-in.go @@ -4,6 +4,10 @@ // operator-in.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + //-------- in term func newInTerm(tk *Token) (inst *term) { @@ -21,19 +25,19 @@ func newInTerm(tk *Token) (inst *term) { // return // } -func evalIn(ctx ExprContext, opTerm *term) (v any, err error) { +func evalIn(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil { return } - if IsList(rightValue) { - list, _ := rightValue.(*ListType) - v = list.indexDeepSameCmp(leftValue) >= 0 - } else if IsDict(rightValue) { - dict, _ := rightValue.(*DictType) - v = dict.hasKey(leftValue) + if kern.IsList(rightValue) { + list, _ := rightValue.(*kern.ListType) + v = list.IndexDeepSameCmp(leftValue) >= 0 + } else if kern.IsDict(rightValue) { + dict, _ := rightValue.(*kern.DictType) + v = dict.HasKey(leftValue) } else { err = opTerm.errIncompatibleTypes(leftValue, rightValue) } diff --git a/operator-include.go b/operator-include.go index 3bd201d..6a4f174 100644 --- a/operator-include.go +++ b/operator-include.go @@ -4,6 +4,10 @@ // operator-include.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + //-------- include term func newIncludeTerm(tk *Token) (inst *term) { @@ -16,7 +20,7 @@ func newIncludeTerm(tk *Token) (inst *term) { } } -func evalInclude(ctx ExprContext, opTerm *term) (v any, err error) { +func evalInclude(ctx kern.ExprContext, opTerm *term) (v any, err error) { var childValue any if childValue, err = opTerm.evalPrefix(ctx); err != nil { @@ -24,8 +28,8 @@ func evalInclude(ctx ExprContext, opTerm *term) (v any, err error) { } count := 0 - if IsList(childValue) { - list, _ := childValue.(*ListType) + if kern.IsList(childValue) { + list, _ := childValue.(*kern.ListType) for i, filePathSpec := range *list { if filePath, ok := filePathSpec.(string); ok { if v, err = EvalFile(ctx, filePath); err == nil { @@ -39,13 +43,13 @@ func evalInclude(ctx ExprContext, opTerm *term) (v any, err error) { break } } - } else if IsString(childValue) { + } else if kern.IsString(childValue) { filePath, _ := childValue.(string) if v, err = EvalFile(ctx, filePath); err == nil { count++ } } else { - err = opTerm.errIncompatibleType(childValue) + err = opTerm.errIncompatiblePrefixPostfixType(childValue) } if err != nil { //v = count diff --git a/operator-index.go b/operator-index.go index 069081b..e3d853f 100644 --- a/operator-index.go +++ b/operator-index.go @@ -4,6 +4,10 @@ // operator-index.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + // -------- index term func newIndexTerm(tk *Token) (inst *term) { return &term{ @@ -15,15 +19,15 @@ func newIndexTerm(tk *Token) (inst *term) { } } -func verifyKey(indexList *ListType) (index any, err error) { +func verifyKey(indexList *kern.ListType) (index any, err error) { index = (*indexList)[0] return } -func verifyIndex(indexTerm *term, indexList *ListType, maxValue int) (index int, err error) { +func verifyIndex(indexTerm *term, indexList *kern.ListType, maxValue int) (index int, err error) { var v int - if v, err = ToGoInt((*indexList)[0], "index expression"); err == nil { + if v, err = kern.ToGoInt((*indexList)[0], "index expression"); err == nil { if v < 0 && v >= -maxValue { v = maxValue + v } @@ -36,11 +40,11 @@ func verifyIndex(indexTerm *term, indexList *ListType, maxValue int) (index int, return } -func verifyRange(indexTerm *term, indexList *ListType, maxValue int) (startIndex, endIndex int, err error) { +func verifyRange(indexTerm *term, indexList *kern.ListType, maxValue int) (startIndex, endIndex int, err error) { v, _ := ((*indexList)[0]).(*intPair) startIndex = v.a endIndex = v.b - if endIndex == ConstLastIndex { + if endIndex == kern.ConstLastIndex { endIndex = maxValue } if startIndex < 0 && startIndex >= -maxValue { @@ -59,9 +63,9 @@ func verifyRange(indexTerm *term, indexList *ListType, maxValue int) (startIndex return } -func evalIndex(ctx ExprContext, opTerm *term) (v any, err error) { +func evalIndex(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any - var indexList *ListType + var indexList *kern.ListType var ok bool if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil { @@ -69,7 +73,7 @@ func evalIndex(ctx ExprContext, opTerm *term) (v any, err error) { } indexTerm := opTerm.children[1] - if indexList, ok = rightValue.(*ListType); !ok { + if indexList, ok = rightValue.(*kern.ListType); !ok { err = opTerm.Errorf("invalid index expression") return } else if len(*indexList) != 1 { @@ -77,9 +81,9 @@ func evalIndex(ctx ExprContext, opTerm *term) (v any, err error) { return } - if IsInteger((*indexList)[0]) { + if kern.IsInteger((*indexList)[0]) { switch unboxedValue := leftValue.(type) { - case *ListType: + case *kern.ListType: var index int if index, err = verifyIndex(indexTerm, indexList, len(*unboxedValue)); err == nil { v = (*unboxedValue)[index] @@ -89,17 +93,17 @@ func evalIndex(ctx ExprContext, opTerm *term) (v any, err error) { if index, err = verifyIndex(indexTerm, indexList, len(unboxedValue)); err == nil { v = string(unboxedValue[index]) } - case *DictType: + case *kern.DictType: v, err = getDictItem(unboxedValue, indexTerm, indexList, rightValue) default: err = opTerm.errIncompatibleTypes(leftValue, rightValue) } } else if isIntPair((*indexList)[0]) { switch unboxedValue := leftValue.(type) { - case *ListType: + case *kern.ListType: var start, end int if start, end, err = verifyRange(indexTerm, indexList, len(*unboxedValue)); err == nil { - sublist := ListType((*unboxedValue)[start:end]) + sublist := kern.ListType((*unboxedValue)[start:end]) v = &sublist } case string: @@ -110,8 +114,8 @@ func evalIndex(ctx ExprContext, opTerm *term) (v any, err error) { default: err = opTerm.errIncompatibleTypes(leftValue, rightValue) } - } else if IsDict(leftValue) { - d := leftValue.(*DictType) + } else if kern.IsDict(leftValue) { + d := leftValue.(*kern.DictType) v, err = getDictItem(d, indexTerm, indexList, rightValue) } else { rightChild := opTerm.children[1] @@ -120,7 +124,7 @@ func evalIndex(ctx ExprContext, opTerm *term) (v any, err error) { return } -func getDictItem(d *DictType, indexTerm *term, indexList *ListType, rightValue any) (v any, err error) { +func getDictItem(d *kern.DictType, indexTerm *term, indexList *kern.ListType, rightValue any) (v any, err error) { var ok bool var indexValue any diff --git a/operator-insert.go b/operator-insert.go index aef289b..7ae3b2e 100644 --- a/operator-insert.go +++ b/operator-insert.go @@ -4,6 +4,10 @@ // operator-insert.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + //-------- prepend term func newPrependTerm(tk *Token) (inst *term) { @@ -26,19 +30,19 @@ func newAppendTerm(tk *Token) (inst *term) { } } -func evalPrepend(ctx ExprContext, opTerm *term) (v any, err error) { +func evalPrepend(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil { return } - if IsList(rightValue) { - list, _ := rightValue.(*ListType) - newList := append(ListType{leftValue}, *list...) + if kern.IsList(rightValue) { + list, _ := rightValue.(*kern.ListType) + newList := append(kern.ListType{leftValue}, *list...) v = &newList if opTerm.children[1].symbol() == SymVariable { - ctx.UnsafeSetVar(opTerm.children[1].source(), v) + ctx.UnsafeSetVar(opTerm.children[1].Source(), v) } } else { err = opTerm.errIncompatibleTypes(leftValue, rightValue) @@ -46,19 +50,19 @@ func evalPrepend(ctx ExprContext, opTerm *term) (v any, err error) { return } -func evalAppend(ctx ExprContext, opTerm *term) (v any, err error) { +func evalAppend(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil { return } - if IsList(leftValue) { - list, _ := leftValue.(*ListType) + if kern.IsList(leftValue) { + list, _ := leftValue.(*kern.ListType) newList := append(*list, rightValue) v = &newList if opTerm.children[0].symbol() == SymVariable { - ctx.UnsafeSetVar(opTerm.children[0].source(), v) + ctx.UnsafeSetVar(opTerm.children[0].Source(), v) } } else { err = opTerm.errIncompatibleTypes(leftValue, rightValue) diff --git a/operator-iter-value.go b/operator-iter-value.go index 0340a5f..efda21c 100644 --- a/operator-iter-value.go +++ b/operator-iter-value.go @@ -4,6 +4,10 @@ // operator-iter-value.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + //-------- iter value term func newIterValueTerm(tk *Token) (inst *term) { @@ -16,17 +20,17 @@ func newIterValueTerm(tk *Token) (inst *term) { } } -func evalIterValue(ctx ExprContext, opTerm *term) (v any, err error) { +func evalIterValue(ctx kern.ExprContext, opTerm *term) (v any, err error) { var childValue any if childValue, err = opTerm.evalPrefix(ctx); err != nil { return } - if it, ok := childValue.(Iterator); ok { + if it, ok := childValue.(kern.Iterator); ok { v, err = it.Current() } else { - err = opTerm.errIncompatibleType(childValue) + err = opTerm.errIncompatiblePrefixPostfixType(childValue) } return } diff --git a/operator-join.go b/operator-join.go index 62c9317..33df15c 100644 --- a/operator-join.go +++ b/operator-join.go @@ -7,6 +7,8 @@ package expr import ( "fmt" "io" + + "git.portale-stac.it/go-pkg/expr/kern" ) //-------- join term @@ -21,35 +23,35 @@ func newJoinTerm(tk *Token) (inst *term) { } } -func evalJoin(ctx ExprContext, opTerm *term) (v any, err error) { +func evalJoin(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any - var itLeft, itRight Iterator + var itLeft, itRight kern.Iterator var item any if err = opTerm.checkOperands(); err != nil { return } - if leftValue, err = opTerm.children[0].compute(ctx); err != nil { + if leftValue, err = opTerm.children[0].Compute(ctx); err != nil { return } - if rightValue, err = opTerm.children[1].compute(ctx); err != nil { + if rightValue, err = opTerm.children[1].Compute(ctx); err != nil { return } if itLeft, err = NewIterator(leftValue); err != nil { - return nil, fmt.Errorf("left operand of JOIN must be an iterable data-source; got %s", TypeName(leftValue)) + return nil, fmt.Errorf("left operand of JOIN must be an iterable data-source; got %s", kern.TypeName(leftValue)) } if itRight, err = NewIterator(rightValue); err != nil { - return nil, fmt.Errorf("right operand of JOIN must be an iterable data-source; got %s", TypeName(rightValue)) + return nil, fmt.Errorf("right operand of JOIN must be an iterable data-source; got %s", kern.TypeName(rightValue)) } - values := newListA() - for _, it := range []Iterator{itLeft, itRight} { + values := kern.NewListA() + for _, it := range []kern.Iterator{itLeft, itRight} { for item, err = it.Next(); err == nil; item, err = it.Next() { - values.appendItem(item) + values.AppendItem(item) } } if err == io.EOF { diff --git a/operator-length.go b/operator-length.go index 7ace415..79a5321 100644 --- a/operator-length.go +++ b/operator-length.go @@ -4,6 +4,10 @@ // operator-length.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + //-------- length term func newLengthTerm(tk *Token) (inst *term) { @@ -16,23 +20,23 @@ func newLengthTerm(tk *Token) (inst *term) { } } -func evalLength(ctx ExprContext, opTerm *term) (v any, err error) { +func evalLength(ctx kern.ExprContext, opTerm *term) (v any, err error) { var childValue any if childValue, err = opTerm.evalPrefix(ctx); err != nil { return } - if IsList(childValue) { - ls, _ := childValue.(*ListType) + if kern.IsList(childValue) { + ls, _ := childValue.(*kern.ListType) v = int64(len(*ls)) - } else if IsString(childValue) { + } else if kern.IsString(childValue) { s, _ := childValue.(string) v = int64(len(s)) - } else if IsDict(childValue) { - m, _ := childValue.(*DictType) + } else if kern.IsDict(childValue) { + m, _ := childValue.(*kern.DictType) v = int64(len(*m)) - } else if it, ok := childValue.(Iterator); ok { + } else if it, ok := childValue.(kern.Iterator); ok { v = int64(it.Count()) // if extIt, ok := childValue.(ExtIterator); ok && extIt.HasOperation(CountName) { // count, _ := extIt.CallOperation(CountName, nil) @@ -41,7 +45,7 @@ func evalLength(ctx ExprContext, opTerm *term) (v any, err error) { // v = int64(it.Index() + 1) // } } else { - err = opTerm.errIncompatibleType(childValue) + err = opTerm.errIncompatiblePrefixPostfixType(childValue) } return } diff --git a/operator-map.go b/operator-map.go index ced7e88..d7c81a5 100644 --- a/operator-map.go +++ b/operator-map.go @@ -7,6 +7,8 @@ package expr import ( "fmt" "io" + + "git.portale-stac.it/go-pkg/expr/kern" ) //-------- map term @@ -21,30 +23,30 @@ func newMapTerm(tk *Token) (inst *term) { } } -func evalMap(ctx ExprContext, opTerm *term) (v any, err error) { +func evalMap(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any - var it Iterator + var it kern.Iterator var item any if err = opTerm.checkOperands(); err != nil { return } - if leftValue, err = opTerm.children[0].compute(ctx); err != nil { + if leftValue, err = opTerm.children[0].Compute(ctx); err != nil { return } if it, err = NewIterator(leftValue); err != nil { - return nil, fmt.Errorf("left operand of MAP must be an iterable data-source; got %s", TypeName(leftValue)) + return nil, fmt.Errorf("left operand of MAP must be an iterable data-source; got %s", kern.TypeName(leftValue)) } - values := newListA() + values := kern.NewListA() for item, err = it.Next(); err == nil; item, err = it.Next() { ctx.SetVar("_", item) ctx.SetVar("_index", it.Index()) ctx.SetVar("_count", it.Count()) - if rightValue, err = opTerm.children[1].compute(ctx); err == nil { - values.appendItem(rightValue) + if rightValue, err = opTerm.children[1].Compute(ctx); err == nil { + values.AppendItem(rightValue) } ctx.DeleteVar("_count") ctx.DeleteVar("_index") diff --git a/operator-plugin.go b/operator-plugin.go index 2a4d3a3..af4049e 100644 --- a/operator-plugin.go +++ b/operator-plugin.go @@ -4,6 +4,10 @@ // operator-plugin.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + //-------- plugin term func newPluginTerm(tk *Token) (inst *term) { @@ -16,7 +20,7 @@ func newPluginTerm(tk *Token) (inst *term) { } } -func evalPlugin(ctx ExprContext, opTerm *term) (v any, err error) { +func evalPlugin(ctx kern.ExprContext, opTerm *term) (v any, err error) { var childValue any var count int @@ -24,7 +28,7 @@ func evalPlugin(ctx ExprContext, opTerm *term) (v any, err error) { return } - if count, err = importPluginFromSearchPath(childValue); err == nil { + if count, err = importPluginFromSearchPath(ctx, childValue); err == nil { v = int64(count) } return diff --git a/operator-post-inc-dec.go b/operator-post-inc-dec.go index 3216a62..0768b37 100644 --- a/operator-post-inc-dec.go +++ b/operator-post-inc-dec.go @@ -4,6 +4,10 @@ // operator-post-inc-dec.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + // -------- post increment term func newPostIncTerm(tk *Token) *term { @@ -17,40 +21,40 @@ func newPostIncTerm(tk *Token) *term { } } -func evalPostInc(ctx ExprContext, opTerm *term) (v any, err error) { +func evalPostInc(ctx kern.ExprContext, opTerm *term) (v any, err error) { var childValue any if childValue, err = opTerm.evalPrefix(ctx); err != nil { return } - if it, ok := childValue.(Iterator); ok { + if it, ok := childValue.(kern.Iterator); ok { var namePrefix string v, err = it.Next() if opTerm.children[0].symbol() == SymVariable { - namePrefix = opTerm.children[0].source() + namePrefix = opTerm.children[0].Source() } ctx.UnsafeSetVar(namePrefix+"_index", it.Index()) if c, err1 := it.Current(); err1 == nil { ctx.UnsafeSetVar(namePrefix+"_current", c) } - if it.HasOperation(KeyName) { - if k, err1 := it.CallOperation(KeyName, nil); err1 == nil { + if it.HasOperation(kern.KeyName) { + if k, err1 := it.CallOperation(kern.KeyName, nil); err1 == nil { ctx.UnsafeSetVar(namePrefix+"_key", k) } } - if it.HasOperation(ValueName) { - if v1, err1 := it.CallOperation(ValueName, nil); err1 == nil { + if it.HasOperation(kern.ValueName) { + if v1, err1 := it.CallOperation(kern.ValueName, nil); err1 == nil { ctx.UnsafeSetVar(namePrefix+"_value", v1) } } - } else if IsInteger(childValue) && opTerm.children[0].symbol() == SymVariable { + } else if kern.IsInteger(childValue) && opTerm.children[0].symbol() == SymVariable { v = childValue i, _ := childValue.(int64) - ctx.SetVar(opTerm.children[0].source(), i+1) + ctx.SetVar(opTerm.children[0].Source(), i+1) } else { - err = opTerm.errIncompatibleType(childValue) + err = opTerm.errIncompatiblePrefixPostfixType(childValue) } return } @@ -68,7 +72,7 @@ func newPostDecTerm(tk *Token) *term { } } -func evalPostDec(ctx ExprContext, opTerm *term) (v any, err error) { +func evalPostDec(ctx kern.ExprContext, opTerm *term) (v any, err error) { var childValue any if childValue, err = opTerm.evalPrefix(ctx); err != nil { return @@ -76,12 +80,12 @@ func evalPostDec(ctx ExprContext, opTerm *term) (v any, err error) { /* if it, ok := childValue.(Iterator); ok { v, err = it.Next() - } else */if IsInteger(childValue) && opTerm.children[0].symbol() == SymVariable { + } else */if kern.IsInteger(childValue) && opTerm.children[0].symbol() == SymVariable { v = childValue i, _ := childValue.(int64) - ctx.SetVar(opTerm.children[0].source(), i-1) + ctx.SetVar(opTerm.children[0].Source(), i-1) } else { - err = opTerm.errIncompatibleType(childValue) + err = opTerm.errIncompatiblePrefixPostfixType(childValue) } return } diff --git a/operator-pre-inc-dec.go b/operator-pre-inc-dec.go index 807f3e6..241c53e 100644 --- a/operator-pre-inc-dec.go +++ b/operator-pre-inc-dec.go @@ -4,6 +4,10 @@ // operator-pre-inc-dec.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + // -------- pre increment term func newPreIncTerm(tk *Token) *term { @@ -17,18 +21,18 @@ func newPreIncTerm(tk *Token) *term { } } -func evalPreInc(ctx ExprContext, opTerm *term) (v any, err error) { +func evalPreInc(ctx kern.ExprContext, opTerm *term) (v any, err error) { var childValue any if childValue, err = opTerm.evalPrefix(ctx); err != nil { return } - if IsInteger(childValue) && opTerm.children[0].symbol() == SymVariable { + if kern.IsInteger(childValue) && opTerm.children[0].symbol() == SymVariable { i := childValue.(int64) + 1 - ctx.SetVar(opTerm.children[0].source(), i) + ctx.SetVar(opTerm.children[0].Source(), i) v = i } else { - err = opTerm.errIncompatibleType(childValue) + err = opTerm.errIncompatiblePrefixPostfixType(childValue) } return } @@ -46,18 +50,18 @@ func newPreDecTerm(tk *Token) *term { } } -func evalPreDec(ctx ExprContext, opTerm *term) (v any, err error) { +func evalPreDec(ctx kern.ExprContext, opTerm *term) (v any, err error) { var childValue any if childValue, err = opTerm.evalPrefix(ctx); err != nil { return } - if IsInteger(childValue) && opTerm.children[0].symbol() == SymVariable { + if kern.IsInteger(childValue) && opTerm.children[0].symbol() == SymVariable { i := childValue.(int64) - 1 - ctx.SetVar(opTerm.children[0].source(), i) + ctx.SetVar(opTerm.children[0].Source(), i) v = i } else { - err = opTerm.errIncompatibleType(childValue) + err = opTerm.errIncompatiblePrefixPostfixType(childValue) } return } diff --git a/operator-prod.go b/operator-prod.go index 1deaf35..af652c6 100644 --- a/operator-prod.go +++ b/operator-prod.go @@ -6,6 +6,8 @@ package expr import ( "strings" + + "git.portale-stac.it/go-pkg/expr/kern" ) //-------- multiply term @@ -21,15 +23,15 @@ func newMultiplyTerm(tk *Token) (inst *term) { } func mulValues(opTerm *term, leftValue, rightValue any) (v any, err error) { - if IsString(leftValue) && IsInteger(rightValue) { + if kern.IsString(leftValue) && kern.IsInteger(rightValue) { s, _ := leftValue.(string) n, _ := rightValue.(int64) v = strings.Repeat(s, int(n)) - } else if isNumOrFract(leftValue) && isNumOrFract(rightValue) { - if IsFloat(leftValue) || IsFloat(rightValue) { - v = numAsFloat(leftValue) * numAsFloat(rightValue) - } else if isFraction(leftValue) || isFraction(rightValue) { - v, err = mulAnyFract(leftValue, rightValue) + } else if kern.IsNumOrFract(leftValue) && kern.IsNumOrFract(rightValue) { + if kern.IsFloat(leftValue) || kern.IsFloat(rightValue) { + v = kern.NumAsFloat(leftValue) * kern.NumAsFloat(rightValue) + } else if kern.IsFraction(leftValue) || kern.IsFraction(rightValue) { + v, err = kern.MulAnyFract(leftValue, rightValue) } else { leftInt, _ := leftValue.(int64) rightInt, _ := rightValue.(int64) @@ -41,7 +43,7 @@ func mulValues(opTerm *term, leftValue, rightValue any) (v any, err error) { return } -func evalMultiply(ctx ExprContext, prodTerm *term) (v any, err error) { +func evalMultiply(ctx kern.ExprContext, prodTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = prodTerm.evalInfix(ctx); err != nil { @@ -64,16 +66,16 @@ func newDivideTerm(tk *Token) (inst *term) { } func divValues(opTerm *term, leftValue, rightValue any) (v any, err error) { - if isNumOrFract(leftValue) && isNumOrFract(rightValue) { - if IsFloat(leftValue) || IsFloat(rightValue) { - d := numAsFloat(rightValue) + if kern.IsNumOrFract(leftValue) && kern.IsNumOrFract(rightValue) { + if kern.IsFloat(leftValue) || kern.IsFloat(rightValue) { + d := kern.NumAsFloat(rightValue) if d == 0.0 { err = opTerm.errDivisionByZero() } else { - v = numAsFloat(leftValue) / d + v = kern.NumAsFloat(leftValue) / d } - } else if isFraction(leftValue) || isFraction(rightValue) { - v, err = divAnyFract(leftValue, rightValue) + } else if kern.IsFraction(leftValue) || kern.IsFraction(rightValue) { + v, err = kern.DivAnyFract(leftValue, rightValue) } else { leftInt, _ := leftValue.(int64) if rightInt, _ := rightValue.(int64); rightInt == 0 { @@ -82,11 +84,11 @@ func divValues(opTerm *term, leftValue, rightValue any) (v any, err error) { v = leftInt / rightInt } } - } else if IsString(leftValue) && IsString(rightValue) { + } else if kern.IsString(leftValue) && kern.IsString(rightValue) { source := leftValue.(string) sep := rightValue.(string) - v = ListFromStrings(strings.Split(source, sep)) - } else if IsString(leftValue) && IsInteger(rightValue) { + v = kern.ListFromStrings(strings.Split(source, sep)) + } else if kern.IsString(leftValue) && kern.IsInteger(rightValue) { source := leftValue.(string) partSize := int(rightValue.(int64)) if partSize == 0 { @@ -105,7 +107,7 @@ func divValues(opTerm *term, leftValue, rightValue any) (v any, err error) { if remainder > 0 { parts = append(parts, source[len(source)-remainder:]) } - v = newList(parts) + v = kern.NewList(parts) } } else { err = opTerm.errIncompatibleTypes(leftValue, rightValue) @@ -113,7 +115,7 @@ func divValues(opTerm *term, leftValue, rightValue any) (v any, err error) { return } -func evalDivide(ctx ExprContext, opTerm *term) (v any, err error) { +func evalDivide(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil { @@ -135,19 +137,19 @@ func newDivideAsFloatTerm(tk *Token) (inst *term) { } } -func evalDivideAsFloat(ctx ExprContext, floatDivTerm *term) (v any, err error) { +func evalDivideAsFloat(ctx kern.ExprContext, floatDivTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = floatDivTerm.evalInfix(ctx); err != nil { return } - if isNumOrFract(leftValue) && isNumOrFract(rightValue) { - d := numAsFloat(rightValue) + if kern.IsNumOrFract(leftValue) && kern.IsNumOrFract(rightValue) { + d := kern.NumAsFloat(rightValue) if d == 0.0 { err = floatDivTerm.errDivisionByZero() } else { - v = numAsFloat(leftValue) / d + v = kern.NumAsFloat(leftValue) / d } } else { err = floatDivTerm.errIncompatibleTypes(leftValue, rightValue) @@ -167,7 +169,7 @@ func newRemainderTerm(tk *Token) (inst *term) { } } func remainderValues(opTerm *term, leftValue, rightValue any) (v any, err error) { - if IsInteger(leftValue) && IsInteger(rightValue) { + if kern.IsInteger(leftValue) && kern.IsInteger(rightValue) { rightInt, _ := rightValue.(int64) if rightInt == 0 { err = opTerm.errDivisionByZero() @@ -181,7 +183,7 @@ func remainderValues(opTerm *term, leftValue, rightValue any) (v any, err error) return } -func evalRemainder(ctx ExprContext, remainderTerm *term) (v any, err error) { +func evalRemainder(ctx kern.ExprContext, remainderTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = remainderTerm.evalInfix(ctx); err != nil { diff --git a/operator-range.go b/operator-range.go index d46a387..beb1760 100644 --- a/operator-range.go +++ b/operator-range.go @@ -4,7 +4,11 @@ // operator-range.go package expr -import "fmt" +import ( + "fmt" + + "git.portale-stac.it/go-pkg/expr/kern" +) // -------- range term type intPair struct { @@ -12,10 +16,10 @@ type intPair struct { } func (p *intPair) TypeName() string { - return TypePair + return kern.TypePair } -func (p *intPair) ToString(opt FmtOpt) string { +func (p *intPair) ToString(opt kern.FmtOpt) string { return fmt.Sprintf("(%d, %d)", p.a, p.b) } @@ -41,21 +45,21 @@ func changeColonToRange(t *term) { } } -func evalRange(ctx ExprContext, opTerm *term) (v any, err error) { +func evalRange(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any if len(opTerm.children) == 0 { leftValue = int64(0) rightValue = int64(-1) } else if len(opTerm.children) == 1 { - if leftValue, err = opTerm.children[0].compute(ctx); err != nil { + if leftValue, err = opTerm.children[0].Compute(ctx); err != nil { return } - rightValue = int64(ConstLastIndex) + rightValue = int64(kern.ConstLastIndex) } else if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil { return } - if !(IsInteger(leftValue) && IsInteger(rightValue)) { + if !(kern.IsInteger(leftValue) && kern.IsInteger(rightValue)) { // err = opTerm.errIncompatibleTypes(leftValue, rightValue) err = errRangeInvalidSpecification(opTerm) return diff --git a/operator-rel.go b/operator-rel.go index 4aed27e..4a2410a 100644 --- a/operator-rel.go +++ b/operator-rel.go @@ -4,7 +4,11 @@ // operator-rel.go package expr -import "reflect" +import ( + "reflect" + + "git.portale-stac.it/go-pkg/expr/kern" +) //-------- equal term @@ -18,25 +22,25 @@ func newEqualTerm(tk *Token) (inst *term) { } } -type deepFuncTemplate func(a, b any) (eq bool, err error) +// type deepFuncTemplate func(a, b any) (eq bool, err error) -func equals(a, b any, deepCmp deepFuncTemplate) (eq bool, err error) { - if isNumOrFract(a) && isNumOrFract(b) { - if IsNumber(a) && IsNumber(b) { - if IsInteger(a) && IsInteger(b) { +func equals(a, b any, deepCmp kern.DeepFuncTemplate) (eq bool, err error) { + if kern.IsNumOrFract(a) && kern.IsNumOrFract(b) { + if kern.IsNumber(a) && kern.IsNumber(b) { + if kern.IsInteger(a) && kern.IsInteger(b) { li, _ := a.(int64) ri, _ := b.(int64) eq = li == ri } else { - eq = numAsFloat(a) == numAsFloat(b) + eq = kern.NumAsFloat(a) == kern.NumAsFloat(b) } } else { var cmp int - if cmp, err = cmpAnyFract(a, b); err == nil { + if cmp, err = kern.CmpAnyFract(a, b); err == nil { eq = cmp == 0 } } - } else if deepCmp != nil && IsList(a) && IsList(b) { + } else if deepCmp != nil && kern.IsList(a) && kern.IsList(b) { eq, err = deepCmp(a, b) } else { eq = reflect.DeepEqual(a, b) @@ -45,7 +49,7 @@ func equals(a, b any, deepCmp deepFuncTemplate) (eq bool, err error) { return } -func evalEqual(ctx ExprContext, opTerm *term) (v any, err error) { +func evalEqual(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil { @@ -68,9 +72,9 @@ func newNotEqualTerm(tk *Token) (inst *term) { } } -func evalNotEqual(ctx ExprContext, opTerm *term) (v any, err error) { +func evalNotEqual(ctx kern.ExprContext, opTerm *term) (v any, err error) { if v, err = evalEqual(ctx, opTerm); err == nil { - b, _ := ToBool(v) + b, _ := kern.ToBool(v) v = !b } return @@ -89,37 +93,37 @@ func newLessTerm(tk *Token) (inst *term) { } func lessThan(self *term, a, b any) (isLess bool, err error) { - if isNumOrFract(a) && isNumOrFract(b) { - if IsNumber(a) && IsNumber(b) { - if IsInteger(a) && IsInteger(b) { + if kern.IsNumOrFract(a) && kern.IsNumOrFract(b) { + if kern.IsNumber(a) && kern.IsNumber(b) { + if kern.IsInteger(a) && kern.IsInteger(b) { li, _ := a.(int64) ri, _ := b.(int64) isLess = li < ri } else { - isLess = numAsFloat(a) < numAsFloat(b) + isLess = kern.NumAsFloat(a) < kern.NumAsFloat(b) } } else { var cmp int - if cmp, err = cmpAnyFract(a, b); err == nil { + if cmp, err = kern.CmpAnyFract(a, b); err == nil { isLess = cmp < 0 } } - } else if IsString(a) && IsString(b) { + } else if kern.IsString(a) && kern.IsString(b) { ls, _ := a.(string) rs, _ := b.(string) isLess = ls < rs // Inclusion test - } else if IsList(a) && IsList(b) { - aList, _ := a.(*ListType) - bList, _ := b.(*ListType) - isLess = len(*aList) < len(*bList) && bList.contains(aList) + } else if kern.IsList(a) && kern.IsList(b) { + aList, _ := a.(*kern.ListType) + bList, _ := b.(*kern.ListType) + isLess = len(*aList) < len(*bList) && bList.Contains(aList) } else { err = self.errIncompatibleTypes(a, b) } return } -func evalLess(ctx ExprContext, opTerm *term) (v any, err error) { +func evalLess(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil { @@ -144,8 +148,8 @@ func newLessEqualTerm(tk *Token) (inst *term) { func lessThanOrEqual(self *term, a, b any) (isLessEq bool, err error) { if isLessEq, err = lessThan(self, a, b); err == nil { if !isLessEq { - if IsList(a) && IsList(b) { - isLessEq, err = sameContent(a, b) + if kern.IsList(a) && kern.IsList(b) { + isLessEq, err = kern.SameContent(a, b) } else { isLessEq, err = equals(a, b, nil) } @@ -154,7 +158,7 @@ func lessThanOrEqual(self *term, a, b any) (isLessEq bool, err error) { return } -func evalLessEqual(ctx ExprContext, opTerm *term) (v any, err error) { +func evalLessEqual(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil { @@ -178,7 +182,7 @@ func newGreaterTerm(tk *Token) (inst *term) { } } -func evalGreater(ctx ExprContext, opTerm *term) (v any, err error) { +func evalGreater(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil { @@ -201,7 +205,7 @@ func newGreaterEqualTerm(tk *Token) (inst *term) { } } -func evalGreaterEqual(ctx ExprContext, opTerm *term) (v any, err error) { +func evalGreaterEqual(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil { diff --git a/operator-selector.go b/operator-selector.go index 6943098..ad7fede 100644 --- a/operator-selector.go +++ b/operator-selector.go @@ -4,6 +4,10 @@ // operator-selector.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + //-------- selector term func newSelectorTerm(tk *Token) (inst *term) { @@ -16,7 +20,7 @@ func newSelectorTerm(tk *Token) (inst *term) { } } -func trySelectorCase(ctx ExprContext, exprValue, caseSel any, caseIndex int) (match bool, selectedValue any, err error) { +func trySelectorCase(ctx kern.ExprContext, exprValue, caseSel any, caseIndex int) (match bool, selectedValue any, err error) { caseData, _ := caseSel.(*selectorCase) if caseData.filterList == nil { selectedValue, err = caseData.caseExpr.Eval(ctx) @@ -38,7 +42,7 @@ func trySelectorCase(ctx ExprContext, exprValue, caseSel any, caseIndex int) (ma } else { var caseValue any for _, caseTerm := range filterList { - if caseValue, err = caseTerm.compute(ctx); err != nil || caseValue == exprValue { + if caseValue, err = caseTerm.Compute(ctx); err != nil || caseValue == exprValue { selectedValue, err = caseData.caseExpr.Eval(ctx) match = true break @@ -49,7 +53,7 @@ func trySelectorCase(ctx ExprContext, exprValue, caseSel any, caseIndex int) (ma return } -func evalSelector(ctx ExprContext, opTerm *term) (v any, err error) { +func evalSelector(ctx kern.ExprContext, opTerm *term) (v any, err error) { var exprValue any var match bool @@ -57,7 +61,7 @@ func evalSelector(ctx ExprContext, opTerm *term) (v any, err error) { return } exprTerm := opTerm.children[0] - if exprValue, err = exprTerm.compute(ctx); err != nil { + if exprValue, err = exprTerm.Compute(ctx); err != nil { return } diff --git a/operator-shift.go b/operator-shift.go index 7c1e9f7..540d48e 100644 --- a/operator-shift.go +++ b/operator-shift.go @@ -4,6 +4,10 @@ // operator-shift.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + //-------- bit right shift term func newRightShiftTerm(tk *Token) (inst *term) { @@ -17,7 +21,7 @@ func newRightShiftTerm(tk *Token) (inst *term) { } func bitRightShift(opTerm *term, leftValue, rightValue any) (v any, err error) { - if IsInteger(leftValue) && IsInteger(rightValue) { + if kern.IsInteger(leftValue) && kern.IsInteger(rightValue) { leftInt := leftValue.(int64) rightInt := rightValue.(int64) v = leftInt >> rightInt @@ -27,7 +31,7 @@ func bitRightShift(opTerm *term, leftValue, rightValue any) (v any, err error) { return } -func evalRightShift(ctx ExprContext, opTerm *term) (v any, err error) { +func evalRightShift(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil { @@ -49,7 +53,7 @@ func newLeftShiftTerm(tk *Token) (inst *term) { } func bitLeftShift(opTerm *term, leftValue, rightValue any) (v any, err error) { - if IsInteger(leftValue) && IsInteger(rightValue) { + if kern.IsInteger(leftValue) && kern.IsInteger(rightValue) { leftInt := leftValue.(int64) rightInt := rightValue.(int64) v = leftInt << rightInt @@ -59,7 +63,7 @@ func bitLeftShift(opTerm *term, leftValue, rightValue any) (v any, err error) { return } -func evalLeftShift(ctx ExprContext, opTerm *term) (v any, err error) { +func evalLeftShift(ctx kern.ExprContext, opTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = opTerm.evalInfix(ctx); err != nil { diff --git a/operator-sign.go b/operator-sign.go index 3dd2e29..4c4b6cf 100644 --- a/operator-sign.go +++ b/operator-sign.go @@ -4,6 +4,10 @@ // operator-sign.go package expr +import ( + "git.portale-stac.it/go-pkg/expr/kern" +) + //-------- plus sign term func newPlusSignTerm(tk *Token) (inst *term) { @@ -28,21 +32,21 @@ func newMinusSignTerm(tk *Token) (inst *term) { } } -func evalSign(ctx ExprContext, opTerm *term) (v any, err error) { +func evalSign(ctx kern.ExprContext, opTerm *term) (v any, err error) { var rightValue any if rightValue, err = opTerm.evalPrefix(ctx); err != nil { return } - if IsFloat(rightValue) { + if kern.IsFloat(rightValue) { if opTerm.tk.Sym == SymChangeSign { f, _ := rightValue.(float64) v = -f } else { v = rightValue } - } else if IsInteger(rightValue) { + } else if kern.IsInteger(rightValue) { if opTerm.tk.Sym == SymChangeSign { i, _ := rightValue.(int64) v = -i @@ -50,7 +54,7 @@ func evalSign(ctx ExprContext, opTerm *term) (v any, err error) { v = rightValue } } else { - err = opTerm.errIncompatibleType(rightValue) + err = opTerm.errIncompatiblePrefixPostfixType(rightValue) } return } diff --git a/operator-sum.go b/operator-sum.go index 31ccdbf..ce5ff8f 100644 --- a/operator-sum.go +++ b/operator-sum.go @@ -7,6 +7,8 @@ package expr import ( "fmt" "slices" + + "git.portale-stac.it/go-pkg/expr/kern" ) //-------- plus term @@ -22,46 +24,46 @@ func newPlusTerm(tk *Token) (inst *term) { } func sumValues(plusTerm *term, leftValue, rightValue any) (v any, err error) { - if (IsString(leftValue) && isNumberString(rightValue)) || (IsString(rightValue) && isNumberString(leftValue)) { + if (kern.IsString(leftValue) && kern.IsNumberString(rightValue)) || (kern.IsString(rightValue) && kern.IsNumberString(leftValue)) { v = fmt.Sprintf("%v%v", leftValue, rightValue) - } else if IsNumber(leftValue) && IsNumber(rightValue) { - if IsFloat(leftValue) || IsFloat(rightValue) { - v = numAsFloat(leftValue) + numAsFloat(rightValue) + } else if kern.IsNumber(leftValue) && kern.IsNumber(rightValue) { + if kern.IsFloat(leftValue) || kern.IsFloat(rightValue) { + v = kern.NumAsFloat(leftValue) + kern.NumAsFloat(rightValue) } else { leftInt, _ := leftValue.(int64) rightInt, _ := rightValue.(int64) v = leftInt + rightInt } - } else if IsList(leftValue) && IsList(rightValue) { - var leftList, rightList *ListType - leftList, _ = leftValue.(*ListType) - rightList, _ = rightValue.(*ListType) + } else if kern.IsList(leftValue) && kern.IsList(rightValue) { + var leftList, rightList *kern.ListType + leftList, _ = leftValue.(*kern.ListType) + rightList, _ = rightValue.(*kern.ListType) - sumList := make(ListType, 0, len(*leftList)+len(*rightList)) + sumList := make(kern.ListType, 0, len(*leftList)+len(*rightList)) sumList = append(sumList, *leftList...) sumList = append(sumList, *rightList...) v = &sumList - } else if (isFraction(leftValue) && IsNumber(rightValue)) || (isFraction(rightValue) && IsNumber(leftValue)) { - if IsFloat(leftValue) || IsFloat(rightValue) { - v = numAsFloat(leftValue) + numAsFloat(rightValue) + } else if (kern.IsFraction(leftValue) && kern.IsNumber(rightValue)) || (kern.IsFraction(rightValue) && kern.IsNumber(leftValue)) { + if kern.IsFloat(leftValue) || kern.IsFloat(rightValue) { + v = kern.NumAsFloat(leftValue) + kern.NumAsFloat(rightValue) } else { - v, err = sumAnyFract(leftValue, rightValue) + v, err = kern.SumAnyFract(leftValue, rightValue) } - } else if IsDict(leftValue) && IsDict(rightValue) { - leftDict, _ := leftValue.(*DictType) - rightDict, _ := rightValue.(*DictType) - c := leftDict.clone() - c.merge(rightDict) + } else if kern.IsDict(leftValue) && kern.IsDict(rightValue) { + leftDict, _ := leftValue.(*kern.DictType) + rightDict, _ := rightValue.(*kern.DictType) + c := leftDict.Clone() + c.Merge(rightDict) v = c - } else if isFraction(leftValue) && isFraction(rightValue) { - v, err = sumAnyFract(leftValue, rightValue) + } else if kern.IsFraction(leftValue) && kern.IsFraction(rightValue) { + v, err = kern.SumAnyFract(leftValue, rightValue) } else { err = plusTerm.errIncompatibleTypes(leftValue, rightValue) } return v, err } -func evalPlus(ctx ExprContext, plusTerm *term) (v any, err error) { +func evalPlus(ctx kern.ExprContext, plusTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = plusTerm.evalInfix(ctx); err != nil { @@ -84,20 +86,20 @@ func newMinusTerm(tk *Token) (inst *term) { } func diffValues(minusTerm *term, leftValue, rightValue any) (v any, err error) { - if isNumOrFract(leftValue) && isNumOrFract(rightValue) { - if IsFloat(leftValue) || IsFloat(rightValue) { - v = numAsFloat(leftValue) - numAsFloat(rightValue) - } else if isFraction(leftValue) || isFraction(rightValue) { - v, err = subAnyFract(leftValue, rightValue) + if kern.IsNumOrFract(leftValue) && kern.IsNumOrFract(rightValue) { + if kern.IsFloat(leftValue) || kern.IsFloat(rightValue) { + v = kern.NumAsFloat(leftValue) - kern.NumAsFloat(rightValue) + } else if kern.IsFraction(leftValue) || kern.IsFraction(rightValue) { + v, err = kern.SubAnyFract(leftValue, rightValue) } else { leftInt, _ := leftValue.(int64) rightInt, _ := rightValue.(int64) v = leftInt - rightInt } - } else if IsList(leftValue) && IsList(rightValue) { - leftList, _ := leftValue.(*ListType) - rightList, _ := rightValue.(*ListType) - diffList := make(ListType, 0, len(*leftList)-len(*rightList)) + } else if kern.IsList(leftValue) && kern.IsList(rightValue) { + leftList, _ := leftValue.(*kern.ListType) + rightList, _ := rightValue.(*kern.ListType) + diffList := make(kern.ListType, 0, len(*leftList)-len(*rightList)) for _, item := range *leftList { if slices.Index(*rightList, item) < 0 { diffList = append(diffList, item) @@ -110,7 +112,7 @@ func diffValues(minusTerm *term, leftValue, rightValue any) (v any, err error) { return } -func evalMinus(ctx ExprContext, minusTerm *term) (v any, err error) { +func evalMinus(ctx kern.ExprContext, minusTerm *term) (v any, err error) { var leftValue, rightValue any if leftValue, rightValue, err = minusTerm.evalInfix(ctx); err != nil { diff --git a/operator-unset.go b/operator-unset.go index 3910464..66f4b01 100644 --- a/operator-unset.go +++ b/operator-unset.go @@ -4,7 +4,11 @@ // operator-unset.go package expr -import "strings" +import ( + "strings" + + "git.portale-stac.it/go-pkg/expr/kern" +) //-------- unset term @@ -18,7 +22,7 @@ func newUnsetTerm(tk *Token) (inst *term) { } } -func deleteContextItem(ctx ExprContext, opTerm *term, item any) (deleted bool, err error) { +func deleteContextItem(ctx kern.ExprContext, opTerm *term, item any) (deleted bool, err error) { if name, ok := item.(string); ok { var size int if strings.HasSuffix(name, "()") { @@ -31,12 +35,12 @@ func deleteContextItem(ctx ExprContext, opTerm *term, item any) (deleted bool, e deleted = ctx.VarCount() < size } } else { - err = opTerm.errIncompatibleType(item) + err = opTerm.errIncompatiblePrefixPostfixType(item) } return } -func evalUnset(ctx ExprContext, opTerm *term) (v any, err error) { +func evalUnset(ctx kern.ExprContext, opTerm *term) (v any, err error) { var childValue any var deleted bool @@ -45,8 +49,8 @@ func evalUnset(ctx ExprContext, opTerm *term) (v any, err error) { } count := 0 - if IsList(childValue) { - list, _ := childValue.(*ListType) + if kern.IsList(childValue) { + list, _ := childValue.(*kern.ListType) for _, item := range *list { if deleted, err = deleteContextItem(ctx, opTerm, item); err != nil { break diff --git a/parser.go b/parser.go index 7a81a9e..f0bf6d9 100644 --- a/parser.go +++ b/parser.go @@ -104,7 +104,7 @@ func (parser *parser) parseFuncDef(scanner *scanner) (tree *term, err error) { param := newTerm(tk) if len(args) > 0 { if pos := paramAlreadyDefined(args, param); pos > 0 { - err = tk.Errorf("parameter %q at position %d already defined at position %d", param.source(), len(args)+1, pos) + err = tk.Errorf("parameter %q at position %d already defined at position %d", param.Source(), len(args)+1, pos) break } } @@ -155,7 +155,7 @@ func (parser *parser) parseFuncDef(scanner *scanner) (tree *term, err error) { func paramAlreadyDefined(args []*term, param *term) (position int) { position = 0 for i, arg := range args { - if arg.source() == param.source() { + if arg.Source() == param.Source() { position = i + 1 } } @@ -397,7 +397,7 @@ func couldBeACollection(t *term) bool { func listSubTree(tree *ast, listTerm *term, allowIndeces bool) (root *term, err error) { var tk *Token if allowIndeces { - tk = NewToken(listTerm.tk.row, listTerm.tk.col, SymIndex, listTerm.source()) + tk = NewToken(listTerm.tk.row, listTerm.tk.col, SymIndex, listTerm.Source()) root = newTerm(tk) if err = tree.addTerm(root); err == nil { err = tree.addTerm(listTerm) diff --git a/plugins.go b/plugins.go index 26374c7..4b25a7c 100644 --- a/plugins.go +++ b/plugins.go @@ -10,6 +10,8 @@ import ( "os" "plugin" "strings" + + "git.portale-stac.it/go-pkg/expr/kern" ) var pluginRegister map[string]*plugin.Plugin @@ -39,12 +41,12 @@ func makePluginName(name string) (decorated string) { return } -func importPlugin( /*ctx ExprContext,*/ dirList []string, name string) (err error) { +func importPlugin(ctx kern.ExprContext, dirList []string, name string) (err error) { var filePath string var p *plugin.Plugin var sym plugin.Symbol var moduleName string - var importFunc func(ExprContext) + var importFunc func(kern.ExprContext) var ok bool decoratedName := makePluginName(name) @@ -71,7 +73,7 @@ func importPlugin( /*ctx ExprContext,*/ dirList []string, name string) (err erro } if deps := *sym.(*[]string); len(deps) > 0 { // var count int - if err = loadModules(dirList, deps); err != nil { + if err = loadModules(ctx, dirList, deps); err != nil { return } } @@ -80,33 +82,35 @@ func importPlugin( /*ctx ExprContext,*/ dirList []string, name string) (err erro return } - if importFunc, ok = sym.(func(ExprContext)); !ok { + if importFunc, ok = sym.(func(kern.ExprContext)); !ok { err = fmt.Errorf("plugin %q does not provide a valid import function", decoratedName) return } registerPlugin(moduleName, p) - importFunc(globalCtx) + if globalCtx := ctx.GetGlobal(); globalCtx != nil { + importFunc(globalCtx) + } return } -func importPluginFromSearchPath(name any) (count int, err error) { +func importPluginFromSearchPath(ctx kern.ExprContext, name any) (count int, err error) { var moduleSpec any - var it Iterator - dirList := buildSearchDirList("plugin", ENV_EXPR_PLUGIN_PATH) + var it kern.Iterator + dirList := buildSearchDirList(ctx, "plugin", ENV_EXPR_PLUGIN_PATH) count = 0 if it, err = NewIterator(name); err != nil { return } for moduleSpec, err = it.Next(); err == nil; moduleSpec, err = it.Next() { if module, ok := moduleSpec.(string); ok { - if err = importPlugin(dirList, module); err != nil { + if err = importPlugin(ctx, dirList, module); err != nil { break } count++ } else { - err = fmt.Errorf("expected string as item nr %d, got %s", it.Index()+1, TypeName(moduleSpec)) + err = fmt.Errorf("expected string as item nr %d, got %s", it.Index()+1, kern.TypeName(moduleSpec)) break } } @@ -116,10 +120,10 @@ func importPluginFromSearchPath(name any) (count int, err error) { return } -func loadModules(dirList []string, moduleNames []string) (err error) { +func loadModules(ctx kern.ExprContext, dirList []string, moduleNames []string) (err error) { for _, name := range moduleNames { - if err1 := importPlugin(dirList, name); err1 != nil { - if !ImportInContext(name) { + if err1 := importPlugin(ctx, dirList, name); err1 != nil { + if !ImportInContext(ctx, name) { err = err1 break } diff --git a/scanner.go b/scanner.go index 644bde0..1b51180 100644 --- a/scanner.go +++ b/scanner.go @@ -11,6 +11,8 @@ import ( "io" "strconv" "strings" + + "git.portale-stac.it/go-pkg/expr/kern" ) type scanner struct { @@ -503,7 +505,7 @@ func (scanner *scanner) parseNumber(firstCh byte) (tk *Token) { if sym == SymFloat { value, err = strconv.ParseFloat(txt, 64) } else if sym == SymFraction { - value, err = makeGeneratingFraction(txt) + value, err = kern.MakeGeneratingFraction(txt) } else { value, err = strconv.ParseInt(txt, numBase, 64) } diff --git a/simple-store.go b/simple-store.go index 1e98292..f5d5768 100644 --- a/simple-store.go +++ b/simple-store.go @@ -7,43 +7,62 @@ package expr import ( "fmt" "slices" + + "git.portale-stac.it/go-pkg/expr/kern" // "strings" ) type SimpleStore struct { - parent ExprContext + global kern.ExprContext + parent kern.ExprContext varStore map[string]any - funcStore map[string]ExprFunc + funcStore map[string]kern.ExprFunc } func NewSimpleStore() *SimpleStore { + global := InitGlobal() + ctx := &SimpleStore{ + global: global, + varStore: make(map[string]any), + funcStore: make(map[string]kern.ExprFunc), + } + return ctx +} + +func NewSimpleStoreWithoutGlobalContext() *SimpleStore { ctx := &SimpleStore{ varStore: make(map[string]any), - funcStore: make(map[string]ExprFunc), + funcStore: make(map[string]kern.ExprFunc), } return ctx } func (ss *SimpleStore) Init() { ss.varStore = make(map[string]any) - ss.funcStore = make(map[string]ExprFunc) + ss.funcStore = make(map[string]kern.ExprFunc) } -func filterRefName(name string) bool { return name[0] != '@' } +func filterRefName(name string) bool { return name[0] != '@' } + //func filterPrivName(name string) bool { return name[0] != '_' } -func (ctx *SimpleStore) SetParent(parentCtx ExprContext) { +func (ctx *SimpleStore) SetParent(parentCtx kern.ExprContext) { ctx.parent = parentCtx } -func (ctx *SimpleStore) GetParent() ExprContext { +func (ctx *SimpleStore) GetParent() kern.ExprContext { return ctx.parent } -func (ctx *SimpleStore) Clone() ExprContext { +func (ctx *SimpleStore) GetGlobal() (globalCtx kern.ExprContext) { + return ctx.global +} + +func (ctx *SimpleStore) Clone() kern.ExprContext { clone := &SimpleStore{ - varStore: CloneFilteredMap(ctx.varStore, filterRefName), - funcStore: CloneFilteredMap(ctx.funcStore, filterRefName), + global: ctx.global, + varStore: kern.CloneFilteredMap(ctx.varStore, filterRefName), + funcStore: kern.CloneFilteredMap(ctx.funcStore, filterRefName), } return clone } @@ -57,19 +76,19 @@ func (ctx *SimpleStore) Clone() ExprContext { // } // } -func (ctx *SimpleStore) ToString(opt FmtOpt) string { +func (ctx *SimpleStore) ToString(opt kern.FmtOpt) string { dict := ctx.ToDict() return dict.ToString(opt) } -func (ctx *SimpleStore) varsToDict(dict *DictType) *DictType { +func (ctx *SimpleStore) varsToDict(dict *kern.DictType) *kern.DictType { names := ctx.EnumVars(nil) slices.Sort(names) for _, name := range ctx.EnumVars(nil) { value, _ := ctx.GetVar(name) - if f, ok := value.(Formatter); ok { + if f, ok := value.(kern.Formatter); ok { (*dict)[name] = f.ToString(0) - } else if _, ok = value.(Functor); ok { + } else if _, ok = value.(kern.Functor); ok { (*dict)[name] = "func(){}" } else { (*dict)[name] = fmt.Sprintf("%v", value) @@ -78,12 +97,12 @@ func (ctx *SimpleStore) varsToDict(dict *DictType) *DictType { return dict } -func (ctx *SimpleStore) funcsToDict(dict *DictType) *DictType { +func (ctx *SimpleStore) funcsToDict(dict *kern.DictType) *kern.DictType { names := ctx.EnumFuncs(func(name string) bool { return true }) slices.Sort(names) for _, name := range names { value, _ := ctx.GetFuncInfo(name) - if formatter, ok := value.(Formatter); ok { + if formatter, ok := value.(kern.Formatter); ok { (*dict)[name] = formatter.ToString(0) } else { (*dict)[name] = fmt.Sprintf("%v", value) @@ -92,20 +111,23 @@ func (ctx *SimpleStore) funcsToDict(dict *DictType) *DictType { return dict } -func (ctx *SimpleStore) ToDict() (dict *DictType) { - dict = MakeDict() - (*dict)["variables"] = ctx.varsToDict(MakeDict()) - (*dict)["functions"] = ctx.funcsToDict(MakeDict()) +func (ctx *SimpleStore) ToDict() (dict *kern.DictType) { + dict = kern.MakeDict() + (*dict)["variables"] = ctx.varsToDict(kern.MakeDict()) + (*dict)["functions"] = ctx.funcsToDict(kern.MakeDict()) return } -func (ctx *SimpleStore) GetVar(varName string) (v any, exists bool) { - v, exists = ctx.varStore[varName] +func (ctx *SimpleStore) GetVar(varName string) (value any, exists bool) { + if value, exists = ctx.varStore[varName]; !exists && ctx.global != nil { + value, exists = ctx.global.GetVar(varName) + } + return } func (ctx *SimpleStore) GetLast() (v any) { - v = ctx.varStore["last"] + v = ctx.varStore[kern.ControlLastResult] return } @@ -116,7 +138,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 := fromGenericAny(value); ok { + if allowedValue, ok := kern.FromGenericAny(value); ok { ctx.varStore[varName] = allowedValue } else { panic(fmt.Errorf("unsupported type %T of value %v", value, value)) @@ -145,16 +167,42 @@ func (ctx *SimpleStore) DeleteVar(varName string) { delete(ctx.varStore, varName) } -func (ctx *SimpleStore) GetFuncInfo(name string) (info ExprFunc, exists bool) { - info, exists = ctx.funcStore[name] +func (ctx *SimpleStore) GetFuncInfo(name string) (info kern.ExprFunc, exists bool) { + info, exists, _ = ctx.GetFuncInfoAndOwner(name) return } -func (ctx *SimpleStore) RegisterFuncInfo(info ExprFunc) { +func (ctx *SimpleStore) GetFuncInfoAndOwner(name string) (info kern.ExprFunc, exists bool, ownerCtx kern.ExprContext) { + if len(name) > 0 { + if info, exists = ctx.GetLocalFuncInfo(name); exists { + ownerCtx = ctx + } else if globalCtx := ctx.GetGlobal(); globalCtx != nil { + if info, exists = globalCtx.GetFuncInfo(name); exists { + ownerCtx = globalCtx + } + } + } + return +} + +func (ctx *SimpleStore) GetLocalFuncInfo(name string) (info kern.ExprFunc, exists bool) { + var v any + if len(name) > 0 { + if v, exists = ctx.GetVar(name); exists && kern.IsFunctor(v) { + f, _ := v.(kern.Functor) + info = f.GetFunc() + } else { + info, exists = ctx.funcStore[name] + } + } + return +} + +func (ctx *SimpleStore) RegisterFuncInfo(info kern.ExprFunc) { ctx.funcStore[info.Name()], _ = info.(*funcInfo) } -func (ctx *SimpleStore) RegisterFunc(name string, functor Functor, returnType string, params []ExprFuncParam) (exprFunc ExprFunc, err error) { +func (ctx *SimpleStore) RegisterFunc(name string, functor kern.Functor, returnType string, params []kern.ExprFuncParam) (exprFunc kern.ExprFunc, err error) { var info *funcInfo if info, err = newFuncInfo(name, functor, returnType, params); err == nil { ctx.funcStore[name] = info @@ -186,7 +234,7 @@ func (ctx *SimpleStore) DeleteFunc(funcName string) { } func (ctx *SimpleStore) Call(name string, args map[string]any) (result any, err error) { - if info, exists := GetLocalFuncInfo(ctx, name); exists { + if info, exists := ctx.GetLocalFuncInfo(name); exists { functor := info.Functor() result, err = functor.InvokeNamed(ctx, name, args) } else { diff --git a/t_bool_test.go b/t_bool_test.go index c864fd0..3c93909 100644 --- a/t_bool_test.go +++ b/t_bool_test.go @@ -7,6 +7,8 @@ package expr import ( "errors" "testing" + + "git.portale-stac.it/go-pkg/expr/kern" ) func TestBool(t *testing.T) { @@ -19,10 +21,10 @@ func TestBool(t *testing.T) { /* 5 */ {`not "true"`, false, nil}, /* 6 */ {`not "false"`, false, nil}, /* 7 */ {`not ""`, true, nil}, - /* 8 */ {`not []`, nil, errors.New(`[1:4] prefix/postfix operator "NOT" do not support operand '[]' [list]`)}, + /* 8 */ {`not []`, nil, errors.New(`[1:4] prefix/postfix operator "NOT" does not support operand '[]' [list]`)}, /* 9 */ {`true and false`, false, nil}, /* 10 */ {`true and []`, nil, errors.New(`[1:9] left operand 'true' [bool] and right operand '[]' [list] are not compatible with operator "AND"`)}, - /* 11 */ {`[] and false`, nil, errors.New(`got list as left operand type of 'AND' operator, it must be bool`)}, + /* 11 */ {`[] and false`, nil, errors.New(`[1:7] operator "AND" does not support operand '[]' [list] on its left side`)}, /* 12 */ {`true or false`, true, nil}, /* 13 */ {`true or []`, true, nil}, /* 14 */ {`[] or false`, nil, errors.New(`got list as left operand type of 'OR' operator, it must be bool`)}, @@ -32,7 +34,7 @@ func TestBool(t *testing.T) { // t.Setenv("EXPR_PATH", ".") - // runTestSuiteSpec(t, section, inputs, 15) + // runTestSuiteSpec(t, section, inputs, 13) runTestSuite(t, section, inputs) } @@ -46,7 +48,7 @@ func TestBoolNoShortcut(t *testing.T) { /* 5 */ {`not "true"`, false, nil}, /* 6 */ {`not "false"`, false, nil}, /* 7 */ {`not ""`, true, nil}, - /* 8 */ {`not []`, nil, `[1:4] prefix/postfix operator "NOT" do not support operand '[]' [list]`}, + /* 8 */ {`not []`, nil, `[1:4] prefix/postfix operator "NOT" does not support operand '[]' [list]`}, /* 9 */ {`true and false`, false, nil}, /* 10 */ {`true and []`, nil, `[1:9] left operand 'true' [bool] and right operand '[]' [list] are not compatible with operator "AND"`}, /* 11 */ {`[] and false`, nil, `[1:7] left operand '[]' [list] and right operand 'false' [bool] are not compatible with operator "AND"`}, @@ -58,10 +60,10 @@ func TestBoolNoShortcut(t *testing.T) { // t.Setenv("EXPR_PATH", ".") ctx := NewSimpleStore() - current := SetCtrl(ctx, ControlBoolShortcut, false) + current := kern.SetCtrl(ctx, kern.ControlBoolShortcut, false) // runCtxTestSuiteSpec(t, ctx, section, inputs, 1) runCtxTestSuite(t, ctx, section, inputs) - SetCtrl(ctx, ControlBoolShortcut, current) + kern.SetCtrl(ctx, kern.ControlBoolShortcut, current) } diff --git a/t_builtin-base_test.go b/t_builtin-base_test.go index 19c9425..fa49f7b 100644 --- a/t_builtin-base_test.go +++ b/t_builtin-base_test.go @@ -6,6 +6,8 @@ package expr import ( "testing" + + "git.portale-stac.it/go-pkg/expr/kern" ) func TestFuncBase(t *testing.T) { @@ -33,10 +35,10 @@ func TestFuncBase(t *testing.T) { /* 19 */ {`isFract(1:3)`, true, nil}, /* 20 */ {`isFract(3:1)`, false, nil}, /* 21 */ {`isRational(3:1)`, true, nil}, - /* 22 */ {`fract("2.2(3)")`, newFraction(67, 30), nil}, - /* 23 */ {`fract("1.21(3)")`, newFraction(91, 75), nil}, - /* 24 */ {`fract(1.21(3))`, newFraction(91, 75), nil}, - /* 25 */ {`fract(1.21)`, newFraction(121, 100), nil}, + /* 22 */ {`fract("2.2(3)")`, kern.NewFraction(67, 30), nil}, + /* 23 */ {`fract("1.21(3)")`, kern.NewFraction(91, 75), nil}, + /* 24 */ {`fract(1.21(3))`, kern.NewFraction(91, 75), nil}, + /* 25 */ {`fract(1.21)`, kern.NewFraction(121, 100), nil}, /* 26 */ {`dec(2)`, float64(2), nil}, /* 27 */ {`dec(2.0)`, float64(2), nil}, /* 28 */ {`dec("2.0")`, float64(2), nil}, @@ -45,8 +47,8 @@ func TestFuncBase(t *testing.T) { /* 31 */ {`dec()`, nil, `dec(): too few params -- expected 1, got 0`}, /* 32 */ {`dec(1,2,3)`, nil, `dec(): too many params -- expected 1, got 3`}, /* 33 */ {`isBool(false)`, true, nil}, - /* 34 */ {`fract(1:2)`, newFraction(1, 2), nil}, - /* 35 */ {`fract(12,2)`, newFraction(6, 1), nil}, + /* 34 */ {`fract(1:2)`, kern.NewFraction(1, 2), nil}, + /* 35 */ {`fract(12,2)`, kern.NewFraction(6, 1), nil}, /* 36 */ {`bool(2)`, true, nil}, /* 37 */ {`bool(1:2)`, true, nil}, /* 38 */ {`bool(1.0)`, true, nil}, diff --git a/t_builtin-fmt_test.go b/t_builtin-fmt_test.go index 40e2bb2..d0dc91a 100644 --- a/t_builtin-fmt_test.go +++ b/t_builtin-fmt_test.go @@ -9,6 +9,8 @@ import ( "bytes" "fmt" "testing" + + "git.portale-stac.it/go-pkg/expr/kern" ) func TestFuncFmt(t *testing.T) { @@ -37,11 +39,11 @@ func TestFmt(t *testing.T) { var b bytes.Buffer ctx := NewSimpleStore() - currentStdout := SetCtrl(ctx, ControlStdout, &b) + currentStdout := kern.SetCtrl(ctx, kern.ControlStdout, &b) runCtxTestSuite(t, ctx, section, inputs) - SetCtrl(ctx, ControlStdout, currentStdout) + kern.SetCtrl(ctx, kern.ControlStdout, currentStdout) if b.String() != text+"\n" { t.Errorf("println(): Got: %q, Want: %q", b.String(), text+"\n") } diff --git a/t_builtin-string_test.go b/t_builtin-string_test.go index 46500c0..dc47af6 100644 --- a/t_builtin-string_test.go +++ b/t_builtin-string_test.go @@ -6,6 +6,8 @@ package expr import ( "testing" + + "git.portale-stac.it/go-pkg/expr/kern" ) func TestFuncString(t *testing.T) { @@ -28,7 +30,7 @@ func TestFuncString(t *testing.T) { /* 14 */ {`builtin "string"; strEndsWith("0123456789", "xyz", "789")`, true, nil}, /* 15 */ {`builtin "string"; strEndsWith("0123456789", "xyz", "0125")`, false, nil}, /* 16 */ {`builtin "string"; strEndsWith("0123456789")`, nil, `strEndsWith(): too few params -- expected 2 or more, got 1`}, - /* 17 */ {`builtin "string"; strSplit("one-two-three", "-")`, newListA("one", "two", "three"), nil}, + /* 17 */ {`builtin "string"; strSplit("one-two-three", "-")`, kern.NewListA("one", "two", "three"), nil}, /* 18 */ {`builtin "string"; strJoin("-", [1, "two", "three"])`, nil, `strJoin(): expected string, got integer (1)`}, /* 19 */ {`builtin "string"; strJoin()`, nil, `strJoin(): too few params -- expected 1 or more, got 0`}, /* 20 */ {`builtin "string"; strUpper("StOp")`, "STOP", nil}, diff --git a/t_common_test.go b/t_common_test.go index 628bcfe..c57572c 100644 --- a/t_common_test.go +++ b/t_common_test.go @@ -9,6 +9,8 @@ import ( "reflect" "strings" "testing" + + "git.portale-stac.it/go-pkg/expr/kern" ) type inputType struct { @@ -17,7 +19,7 @@ type inputType struct { wantErr any } -func runCtxTestSuiteSpec(t *testing.T, ctx ExprContext, section string, inputs []inputType, spec ...int) { +func runCtxTestSuiteSpec(t *testing.T, ctx kern.ExprContext, section string, inputs []inputType, spec ...int) { succeeded := 0 failed := 0 for _, count := range spec { @@ -36,7 +38,7 @@ func runTestSuiteSpec(t *testing.T, section string, inputs []inputType, spec ... runCtxTestSuiteSpec(t, nil, section, inputs, spec...) } -func runCtxTestSuite(t *testing.T, ctx ExprContext, section string, inputs []inputType) { +func runCtxTestSuite(t *testing.T, ctx kern.ExprContext, section string, inputs []inputType) { succeeded := 0 failed := 0 @@ -68,8 +70,8 @@ func getWantedError(input *inputType) error { return wantErr } -func doTest(t *testing.T, ctx ExprContext, section string, input *inputType, count int) (good bool) { - var expr Expr +func doTest(t *testing.T, ctx kern.ExprContext, section string, input *inputType, count int) (good bool) { + var ast Expr var gotResult any var gotErr error var eq, eqDone bool @@ -87,13 +89,13 @@ func doTest(t *testing.T, ctx ExprContext, section string, input *inputType, cou scanner := NewScanner(r, DefaultTranslations()) good = true - if expr, gotErr = parser.Parse(scanner); gotErr == nil { - gotResult, gotErr = expr.Eval(ctx) + if ast, gotErr = parser.Parse(scanner); gotErr == nil { + gotResult, gotErr = ast.Eval(ctx) } if input.wantResult != nil && gotResult != nil { - if ls1, ok := input.wantResult.(*ListType); ok { - if ls2, ok := gotResult.(*ListType); ok { + if ls1, ok := input.wantResult.(*kern.ListType); ok { + if ls2, ok := gotResult.(*kern.ListType); ok { eq = ls1.Equals(*ls2) eqDone = true } @@ -105,7 +107,7 @@ func doTest(t *testing.T, ctx ExprContext, section string, input *inputType, cou } if !eq /*gotResult != input.wantResult*/ { - t.Errorf("%d: `%s` -> result = %v [%s], want = %v [%s]", count, input.source, gotResult, TypeName(gotResult), input.wantResult, TypeName(input.wantResult)) + t.Errorf("%d: `%s` -> result = %v [%s], want = %v [%s]", count, input.source, gotResult, kern.TypeName(gotResult), input.wantResult, kern.TypeName(input.wantResult)) good = false } diff --git a/t_context_test.go b/t_context_test.go new file mode 100644 index 0000000..5d0d30f --- /dev/null +++ b/t_context_test.go @@ -0,0 +1,60 @@ +// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// t_context_test.go +package expr + +import ( + "testing" +) + +func TestCtrlSet(t *testing.T) { + section := "Context" + varName := "_test_var" + varValue := "test-value" + prevValue := "test-prev" + + ctx := NewSimpleStore() + GlobalCtrlSet(ctx, varName, prevValue) + if v := GlobalCtrlSet(ctx, varName, varValue); v != nil { + if s, ok := v.(string); ok { + if s != prevValue { + t.Errorf(`%s -- CtrlSet(%q, %q) should have returned %q, got %q`, section, varName, varValue, varValue, s) + } + } else { + t.Errorf(`%s -- CtrlSet(%q, %q) should have returned a string, got %v [%T]`, section, varName, varValue, v, v) + } + } else { + t.Errorf(`%s -- CtrlSet(%q, %q) should have returned a value, got nil`, section, varName, varValue) + } +} + +func TestCtrlGet(t *testing.T) { + section := "Context" + varName := "_test_var" + varValue := "test-value" + + ctx := NewSimpleStore() + GlobalCtrlSet(ctx, varName, varValue) + if v := GlobalCtrlGet(ctx, varName); v != nil { + if s, ok := v.(string); ok { + if s != "test-value" { + t.Errorf(`%s -- CtrlGet(%q) should have returned %q, got %q`, section, varName, varValue, s) + } + } else { + t.Errorf(`%s -- CtrlGet(%q) should have returned a string, got %v [%T]`, section, varName, v, v) + } + } else { + t.Errorf(`%s -- CtrlGet(%q) should have returned a value, got nil`, section, varName) + } +} + +func TestCtrlGetNotDefined(t *testing.T) { + section := "Context" + varName := "_test_var" + + ctx := NewSimpleStore() + if v := GlobalCtrlGet(ctx, varName); v != nil { + t.Errorf(`%s -- CtrlGet(%q) should have returned nil, got %v`, section, varName, v) + } +} diff --git a/t_dict_test.go b/t_dict_test.go index ef9bfe7..1e58bdc 100644 --- a/t_dict_test.go +++ b/t_dict_test.go @@ -9,6 +9,8 @@ import ( "strings" "testing" + + "git.portale-stac.it/go-pkg/expr/kern" ) func TestDictParser(t *testing.T) { @@ -37,7 +39,7 @@ func TestDictParser(t *testing.T) { //"b":2, "c":3 }`, map[any]any{"a": 1, "c": 3}, nil}, - } + } succeeded := 0 failed := 0 @@ -51,7 +53,7 @@ func TestDictParser(t *testing.T) { var gotResult any var gotErr error - ctx := NewSimpleStore() + ctx := NewSimpleStoreWithoutGlobalContext() ctx.SetVar("var1", int64(123)) ctx.SetVar("var2", "abc") ImportMathFuncs(ctx) @@ -118,11 +120,11 @@ func TestDictToStringMultiLine(t *testing.T) { want := `{ "first": 1 }` - args := map[any]*term{ + args := map[any]any{ "first": newLiteralTerm(NewValueToken(0, 0, SymInteger, "1", 1)), } - dict := newDict(args) - got := dict.ToString(MultiLine) + dict := kern.NewDict(args) + got := dict.ToString(kern.MultiLine) // fmt.Printf("got=%q\n", got) if good = got == want; !good { @@ -140,10 +142,10 @@ func TestDictToString(t *testing.T) { var good bool section := "dict-ToString-SL" want := `{"first": 1}` - args := map[any]*term{ + args := map[any]any{ "first": newLiteralTerm(NewValueToken(0, 0, SymInteger, "1", 1)), } - dict := newDict(args) + dict := kern.NewDict(args) got := dict.ToString(0) // fmt.Printf("got=%q\n", got) diff --git a/t_expr_test.go b/t_expr_test.go index 0b59f77..694f629 100644 --- a/t_expr_test.go +++ b/t_expr_test.go @@ -6,6 +6,8 @@ package expr import ( "testing" + + "git.portale-stac.it/go-pkg/expr/kern" ) func TestExpr(t *testing.T) { @@ -29,7 +31,7 @@ func TestExpr(t *testing.T) { /* 15 */ {`a=3; a*=2)+1; a`, nil, `[1:11] unexpected token ")"`}, /* 16 */ {`v=[2]; a=1; v[a-=1]=5; v[0]`, int64(5), nil}, /* 17 */ {`true ? {"a"} :: {"b"}`, "a", nil}, - /* 18 */ {`$$`, NewDict(map[any]any{"variables": NewDict(nil), "functions": NewDict(nil)}), nil}, + /* 18 */ {`$$`, kern.NewDict(map[any]any{"variables": kern.NewDict(nil), "functions": kern.NewDict(nil)}), nil}, ///* 19 */ {`$$global`, NewDict(map[any]any{"variables": NewDict(nil), "functions": NewDict(nil)}), nil}, /* 19 */ {` ds={ diff --git a/t_fractions_test.go b/t_fractions_test.go index 6d8fc15..7a79369 100644 --- a/t_fractions_test.go +++ b/t_fractions_test.go @@ -6,43 +6,45 @@ package expr import ( "testing" + + "git.portale-stac.it/go-pkg/expr/kern" ) func TestFractionsParser(t *testing.T) { section := "Fraction" inputs := []inputType{ - /* 1 */ {`1:2`, newFraction(1, 2), nil}, - /* 2 */ {`1:2 + 1`, newFraction(3, 2), nil}, - /* 3 */ {`1:2 - 1`, newFraction(-1, 2), nil}, - /* 4 */ {`1:2 * 1`, newFraction(1, 2), nil}, - /* 5 */ {`1:2 * 2:3`, newFraction(2, 6), nil}, - /* 6 */ {`1:2 / 2:3`, newFraction(3, 4), nil}, + /* 1 */ {`1:2`, kern.NewFraction(1, 2), nil}, + /* 2 */ {`1:2 + 1`, kern.NewFraction(3, 2), nil}, + /* 3 */ {`1:2 - 1`, kern.NewFraction(-1, 2), nil}, + /* 4 */ {`1:2 * 1`, kern.NewFraction(1, 2), nil}, + /* 5 */ {`1:2 * 2:3`, kern.NewFraction(2, 6), nil}, + /* 6 */ {`1:2 / 2:3`, kern.NewFraction(3, 4), nil}, /* 7 */ {`1:"5"`, nil, `denominator must be integer, got string (5)`}, /* 8 */ {`"1":5`, nil, `numerator must be integer, got string (1)`}, - /* 9 */ {`1:+5`, newFraction(1, 5), nil}, - /* 10 */ {`1:(-2)`, newFraction(-1, 2), nil}, - /* 11 */ {`builtin "math.arith"; add(1:2, 2:3)`, newFraction(7, 6), nil}, + /* 9 */ {`1:+5`, kern.NewFraction(1, 5), nil}, + /* 10 */ {`1:(-2)`, kern.NewFraction(-1, 2), nil}, + /* 11 */ {`builtin "math.arith"; add(1:2, 2:3)`, kern.NewFraction(7, 6), nil}, /* 12 */ {`builtin "math.arith"; add(1:2, 1.0, 2)`, float64(3.5), nil}, - /* 13 */ {`builtin "math.arith"; mul(1:2, 2:3)`, newFraction(2, 6), nil}, + /* 13 */ {`builtin "math.arith"; mul(1:2, 2:3)`, kern.NewFraction(2, 6), nil}, /* 14 */ {`builtin "math.arith"; mul(1:2, 1.0, 2)`, float64(1.0), nil}, /* 15 */ {`1:0`, nil, `[1:3] division by zero`}, - /* 16 */ {`fract(-0.5)`, newFraction(-1, 2), nil}, - /* 17 */ {`fract("")`, (*FractionType)(nil), `bad syntax`}, - /* 18 */ {`fract("-1")`, newFraction(-1, 1), nil}, - /* 19 */ {`fract("+1")`, newFraction(1, 1), nil}, - /* 20 */ {`fract("1a")`, (*FractionType)(nil), `strconv.ParseInt: parsing "1a": invalid syntax`}, + /* 16 */ {`fract(-0.5)`, kern.NewFraction(-1, 2), nil}, + /* 17 */ {`fract("")`, (*kern.FractionType)(nil), `bad syntax`}, + /* 18 */ {`fract("-1")`, kern.NewFraction(-1, 1), nil}, + /* 19 */ {`fract("+1")`, kern.NewFraction(1, 1), nil}, + /* 20 */ {`fract("1a")`, (*kern.FractionType)(nil), `strconv.ParseInt: parsing "1a": invalid syntax`}, /* 21 */ {`fract(1,0)`, nil, `fract(): division by zero`}, /* 22 */ {`string(1:2)`, "1:2", nil}, /* 23 */ {`1+1:2+0.5`, float64(2), nil}, /* 24 */ {`1:(2-2)`, nil, `[1:3] division by zero`}, - /* 25 */ {`[0,1][1-1]:1`, newFraction(0, 1), nil}, + /* 25 */ {`[0,1][1-1]:1`, kern.NewFraction(0, 1), nil}, } // runTestSuiteSpec(t, section, inputs, 25) runTestSuite(t, section, inputs) } func TestFractionToStringSimple(t *testing.T) { - source := newFraction(1, 2) + source := kern.NewFraction(1, 2) want := "1:2" got := source.ToString(0) if got != want { @@ -51,18 +53,18 @@ func TestFractionToStringSimple(t *testing.T) { } func TestFractionToStringMultiline(t *testing.T) { - source := newFraction(1, 2) + source := kern.NewFraction(1, 2) want := "1\n-\n2" - got := source.ToString(MultiLine) + got := source.ToString(kern.MultiLine) if got != want { t.Errorf(`(1,2) -> result = %v [%T], want = %v [%T]`, got, got, want, want) } } func TestToStringMultilineTty(t *testing.T) { - source := newFraction(-1, 2) + source := kern.NewFraction(-1, 2) want := "\x1b[4m-1\x1b[0m\n 2" - got := source.ToString(MultiLine | TTY) + got := source.ToString(kern.MultiLine | kern.TTY) if got != want { t.Errorf(`(1,2) -> result = %#v [%T], want = %#v [%T]`, got, got, want, want) } diff --git a/t_funcs_test.go b/t_funcs_test.go index 95492af..e3118df 100644 --- a/t_funcs_test.go +++ b/t_funcs_test.go @@ -6,6 +6,8 @@ package expr import ( "testing" + + "git.portale-stac.it/go-pkg/expr/kern" ) func TestFuncs(t *testing.T) { @@ -47,12 +49,12 @@ func TestFuncs(t *testing.T) { runTestSuite(t, section, inputs) } -func dummy(ctx ExprContext, name string, args map[string]any) (result any, err error) { +func dummy(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { return } func TestFunctionToStringSimple(t *testing.T) { - source := NewGolangFunctor(dummy) + source := kern.NewGolangFunctor(dummy) want := "func(){}" got := source.ToString(0) if got != want { @@ -61,8 +63,8 @@ func TestFunctionToStringSimple(t *testing.T) { } func TestFunctionGetFunc(t *testing.T) { - source := NewGolangFunctor(dummy) - want := ExprFunc(nil) + source := kern.NewGolangFunctor(dummy) + want := kern.ExprFunc(nil) got := source.GetFunc() if got != want { t.Errorf(`(func() -> result = %v [%T], want = %v [%T]`, got, got, want, want) @@ -76,16 +78,16 @@ func TestGoFunction(t *testing.T) { /* 2 */ {`myName("Peppino")`, "Peppino", nil}, } - myName := func(ctx ExprContext, name string, args map[string]any) (result any, err error) { + myName := func(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) { var ok bool if result, ok = args["name"].(string); !ok { - err = ErrWrongParamType(name, "name", TypeString, args["name"]) + err = kern.ErrWrongParamType(name, "name", kern.TypeString, args["name"]) } return } - ctx := NewSimpleStore() - ctx.RegisterFunc("myName", NewGolangFunctor(myName), TypeString, []ExprFuncParam{ + ctx := NewSimpleStoreWithoutGlobalContext() + ctx.RegisterFunc("myName", kern.NewGolangFunctor(myName), kern.TypeString, []kern.ExprFuncParam{ NewFuncParamFlagDef("name", PfOptional|PfDefault, "Celestino Amoroso"), }) diff --git a/t_helpers_test.go b/t_helpers_test.go index 7858266..ecc3f52 100644 --- a/t_helpers_test.go +++ b/t_helpers_test.go @@ -53,7 +53,7 @@ import ( func TestEvalString(t *testing.T) { - ctx := NewSimpleStore() + ctx := NewSimpleStoreWithoutGlobalContext() ctx.SetVar("a", uint8(1)) ctx.SetVar("b", int8(2)) ctx.SetVar("f", 2.0) diff --git a/t_iter-list_test.go b/t_iter-list_test.go index c26088e..1aa472b 100644 --- a/t_iter-list_test.go +++ b/t_iter-list_test.go @@ -7,10 +7,12 @@ package expr import ( "io" "testing" + + "git.portale-stac.it/go-pkg/expr/kern" ) func TestNewListIterator(t *testing.T) { - list := newListA("a", "b", "c", "d") + list := kern.NewListA("a", "b", "c", "d") it := NewListIterator(list, []any{1, 3, 1}) if item, err := it.Next(); err != nil { t.Errorf("error: %v", err) @@ -22,7 +24,7 @@ func TestNewListIterator(t *testing.T) { } func TestNewListIterator2(t *testing.T) { - list := newListA("a", "b", "c", "d") + list := kern.NewListA("a", "b", "c", "d") it := NewListIterator(list, []any{3, 1, -1}) if item, err := it.Next(); err != nil { t.Errorf("error: %v", err) @@ -34,7 +36,7 @@ func TestNewListIterator2(t *testing.T) { } func TestNewListIterator3(t *testing.T) { - list := newListA("a", "b", "c", "d") + list := kern.NewListA("a", "b", "c", "d") it := NewListIterator(list, []any{1, -1, 1}) if item, err := it.Next(); err != nil { t.Errorf("error: %v", err) @@ -90,7 +92,7 @@ func TestNewIterList5(t *testing.T) { } func TestNewIterList6(t *testing.T) { - list := newListA("a", "b", "c", "d") + list := kern.NewListA("a", "b", "c", "d") it1, _ := NewIterator(list) it, _ := NewIterator(it1) if item, err := it.Next(); err != nil { @@ -101,6 +103,7 @@ func TestNewIterList6(t *testing.T) { t.Logf("Next: %v", item) } } + func TestNewString(t *testing.T) { list := "123" it, _ := NewIterator(list) @@ -111,7 +114,7 @@ func TestNewString(t *testing.T) { func TestHasOperation(t *testing.T) { - list := newListA("a", "b", "c", "d") + list := kern.NewListA("a", "b", "c", "d") it := NewListIterator(list, []any{1, 3, 1}) hasOp := it.HasOperation("reset") if !hasOp { @@ -121,7 +124,7 @@ func TestHasOperation(t *testing.T) { func TestCallOperationReset(t *testing.T) { - list := newListA("a", "b", "c", "d") + list := kern.NewListA("a", "b", "c", "d") it := NewListIterator(list, []any{1, 3, 1}) if v, err := it.CallOperation("reset", nil); err != nil { t.Errorf("Error on CallOperation(reset): %v", err) @@ -132,7 +135,7 @@ func TestCallOperationReset(t *testing.T) { func TestCallOperationIndex(t *testing.T) { - list := newListA("a", "b", "c", "d") + list := kern.NewListA("a", "b", "c", "d") it := NewListIterator(list, []any{1, 3, 1}) if v, err := it.CallOperation("index", nil); err != nil { t.Errorf("Error on CallOperation(index): %v", err) @@ -143,7 +146,7 @@ func TestCallOperationIndex(t *testing.T) { func TestCallOperationCount(t *testing.T) { - list := newListA("a", "b", "c", "d") + list := kern.NewListA("a", "b", "c", "d") it := NewListIterator(list, []any{1, 3, 1}) if v, err := it.CallOperation("count", nil); err != nil { t.Errorf("Error on CallOperation(count): %v", err) @@ -154,7 +157,7 @@ func TestCallOperationCount(t *testing.T) { func TestCallOperationUnknown(t *testing.T) { - list := newListA("a", "b", "c", "d") + list := kern.NewListA("a", "b", "c", "d") it := NewListIterator(list, []any{1, 3, 1}) if v, err := it.CallOperation("unknown", nil); err == nil { t.Errorf("Expected error on CallOperation(unknown), got %v", v) diff --git a/t_iterator_test.go b/t_iterator_test.go index 9857aa9..c85104e 100644 --- a/t_iterator_test.go +++ b/t_iterator_test.go @@ -4,7 +4,11 @@ // t_iterator_test.go package expr -import "testing" +import ( + "testing" + + "git.portale-stac.it/go-pkg/expr/kern" +) func TestIteratorParser(t *testing.T) { section := "Iterator" @@ -30,8 +34,8 @@ func TestIteratorParser(t *testing.T) { /* 19 */ {`it=$({1:"one",2:"two",3:"three"}); it++`, int64(1), nil}, /* 20 */ {`it=$({1:"one",2:"two",3:"three"}, "default", "value"); it++`, "one", nil}, /* 21 */ {`it=$({1:"one",2:"two",3:"three"}, "desc", "key"); it++`, int64(3), nil}, - /* 22 */ {`it=$({1:"one",2:"two",3:"three"}, "asc", "item"); it++`, NewList([]any{int64(1), "one"}), nil}, - /* 23 */ {`builtin "os.file"; fileReadIterator("test-file.txt") map ${_index}`, NewList([]any{int64(0), int64(1)}), nil}, + /* 22 */ {`it=$({1:"one",2:"two",3:"three"}, "asc", "item"); it++`, kern.NewList([]any{int64(1), "one"}), nil}, + /* 23 */ {`builtin "os.file"; fileReadIterator("test-file.txt") map ${_index}`, kern.NewList([]any{int64(0), int64(1)}), nil}, /* 24 */ {`builtin "os.file"; #(fileReadIterator("test-file.txt") filter (#${_} == 2))`, int64(0), nil}, /* 25 */ {`builtin "os.file"; #(fileReadIterator("test-file.txt") filter (#${_} == 3))`, int64(2), nil}, } diff --git a/t_list_test.go b/t_list_test.go index a92ad37..bd89c7e 100644 --- a/t_list_test.go +++ b/t_list_test.go @@ -6,52 +6,54 @@ package expr import ( "testing" + + "git.portale-stac.it/go-pkg/expr/kern" ) func TestListParser(t *testing.T) { section := "List" inputs := []inputType{ - /* 1 */ {`[]`, newListA(), nil}, - /* 2 */ {`[1,2,3]`, newListA(int64(1), int64(2), int64(3)), nil}, - /* 3 */ {`[1,2,"hello"]`, newListA(int64(1), int64(2), "hello"), nil}, - /* 4 */ {`[1+2, not true, "hello"]`, newListA(int64(3), false, "hello"), nil}, - /* 5 */ {`[1,2]+[3]`, newListA(int64(1), int64(2), int64(3)), nil}, - /* 6 */ {`[1,4,3,2]-[3]`, newListA(int64(1), int64(4), int64(2)), nil}, - /* 7 */ {`add([1,4,3,2])`, int64(10), nil}, - /* 8 */ {`add([1,[2,2],3,2])`, int64(10), nil}, - /* 9 */ {`mul([1,4,3.0,2])`, float64(24.0), nil}, - /* 10 */ {`add([1,"hello"])`, nil, `add(): param nr 2 (2 in 1) has wrong type string, number expected`}, + /* 1 */ {`[]`, kern.NewListA(), nil}, + /* 2 */ {`[1,2,3]`, kern.NewListA(int64(1), int64(2), int64(3)), nil}, + /* 3 */ {`[1,2,"hello"]`, kern.NewListA(int64(1), int64(2), "hello"), nil}, + /* 4 */ {`[1+2, not true, "hello"]`, kern.NewListA(int64(3), false, "hello"), nil}, + /* 5 */ {`[1,2]+[3]`, kern.NewListA(int64(1), int64(2), int64(3)), nil}, + /* 6 */ {`[1,4,3,2]-[3]`, kern.NewListA(int64(1), int64(4), int64(2)), nil}, + /* 7 */ {`builtin "math.arith"; add([1,4,3,2])`, int64(10), nil}, + /* 8 */ {`builtin "math.arith"; add([1,[2,2],3,2])`, int64(10), nil}, + /* 9 */ {`builtin "math.arith"; mul([1,4,3.0,2])`, float64(24.0), nil}, + /* 10 */ {`builtin "math.arith"; add([1,"hello"])`, nil, `add(): param nr 2 (2 in 1) has wrong type string, number expected`}, /* 11 */ {`[a=1,b=2,c=3] but a+b+c`, int64(6), nil}, - /* 12 */ {`[1,2,3] <+ 2+2`, newListA(int64(1), int64(2), int64(3), int64(4)), nil}, - /* 13 */ {`2-1 +> [2,3]`, newListA(int64(1), int64(2), int64(3)), nil}, + /* 12 */ {`[1,2,3] <+ 2+2`, kern.NewListA(int64(1), int64(2), int64(3), int64(4)), nil}, + /* 13 */ {`2-1 +> [2,3]`, kern.NewListA(int64(1), int64(2), int64(3)), nil}, /* 14 */ {`[1,2,3][1]`, int64(2), nil}, /* 15 */ {`ls=[1,2,3] but ls[1]`, int64(2), nil}, /* 16 */ {`ls=[1,2,3] but ls[-1]`, int64(3), nil}, /* 17 */ {`list=["one","two","three"]; list[10]`, nil, `[1:34] index 10 out of bounds`}, - /* 18 */ {`["a", "b", "c"]`, newListA("a", "b", "c"), nil}, - /* 19 */ {`["a", "b", "c"]`, newList([]any{"a", "b", "c"}), nil}, + /* 18 */ {`["a", "b", "c"]`, kern.NewListA("a", "b", "c"), nil}, + /* 19 */ {`["a", "b", "c"]`, kern.NewList([]any{"a", "b", "c"}), nil}, /* 20 */ {`#["a", "b", "c"]`, int64(3), nil}, /* 21 */ {`"b" in ["a", "b", "c"]`, true, nil}, - /* 22 */ {`a=[1,2]; (a)<+3`, newListA(int64(1), int64(2), int64(3)), nil}, - /* 23 */ {`a=[1,2]; (a)<+3; a`, newListA(int64(1), int64(2)), nil}, + /* 22 */ {`a=[1,2]; (a)<+3`, kern.NewListA(int64(1), int64(2), int64(3)), nil}, + /* 23 */ {`a=[1,2]; (a)<+3; a`, kern.NewListA(int64(1), int64(2)), nil}, /* 24 */ {`["a","b","c","d"][1]`, "b", nil}, /* 25 */ {`["a","b","c","d"][1,1]`, nil, `[1:19] one index only is allowed`}, - /* 26 */ {`[0,1,2,3,4][:]`, newListA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil}, + /* 26 */ {`[0,1,2,3,4][:]`, kern.NewListA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil}, /* 27 */ {`["a", "b", "c"] <+ ;`, nil, `[1:18] infix operator "<+" requires two non-nil operands, got 1`}, /* 28 */ {`2 << 3;`, int64(16), nil}, /* 29 */ {`but +> ["a", "b", "c"]`, nil, `[1:6] infix operator "+>" requires two non-nil operands, got 0`}, /* 30 */ {`2 >> 3;`, int64(0), nil}, - /* 31 */ {`a=[1,2]; a<+3`, newListA(int64(1), int64(2), int64(3)), nil}, - /* 32 */ {`a=[1,2]; 5+>a`, newListA(int64(5), int64(1), int64(2)), nil}, - /* 33 */ {`L=[1,2]; L[0]=9; L`, newListA(int64(9), int64(2)), nil}, + /* 31 */ {`a=[1,2]; a<+3`, kern.NewListA(int64(1), int64(2), int64(3)), nil}, + /* 32 */ {`a=[1,2]; 5+>a`, kern.NewListA(int64(5), int64(1), int64(2)), nil}, + /* 33 */ {`L=[1,2]; L[0]=9; L`, kern.NewListA(int64(9), int64(2)), nil}, /* 34 */ {`L=[1,2]; L[5]=9; L`, nil, `index 5 out of bounds (0, 1)`}, /* 35 */ {`L=[1,2]; L[]=9; L`, nil, `[1:12] index/key specification expected, got [] [list]`}, /* 36 */ {`L=[1,2]; L[nil]=9;`, nil, `[1:12] index/key is nil`}, - /* 37 */ {`[0,1,2,3,4][2:3]`, newListA(int64(2)), nil}, - /* 38 */ {`[0,1,2,3,4][3:-1]`, newListA(int64(3)), nil}, - /* 30 */ {`[0,1,2,3,4][-3:-1]`, newListA(int64(2), int64(3)), nil}, - /* 40 */ {`[0,1,2,3,4][0:]`, newListA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil}, + /* 37 */ {`[0,1,2,3,4][2:3]`, kern.NewListA(int64(2)), nil}, + /* 38 */ {`[0,1,2,3,4][3:-1]`, kern.NewListA(int64(3)), nil}, + /* 30 */ {`[0,1,2,3,4][-3:-1]`, kern.NewListA(int64(2), int64(3)), nil}, + /* 40 */ {`[0,1,2,3,4][0:]`, kern.NewListA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil}, } // t.Setenv("EXPR_PATH", ".") diff --git a/t_operator_test.go b/t_operator_test.go index b40134e..d1ed6ea 100644 --- a/t_operator_test.go +++ b/t_operator_test.go @@ -6,6 +6,8 @@ package expr import ( "testing" + + "git.portale-stac.it/go-pkg/expr/kern" ) func TestOperator(t *testing.T) { @@ -27,17 +29,17 @@ func TestOperator(t *testing.T) { /* 14 */ {`0x1X`, nil, `[1:5] two adjacent operators: "1" and "X"`}, /* 15 */ {`0o10`, int64(8), nil}, /* 16 */ {`0b10`, int64(2), nil}, - /* 17 */ {`~true`, nil, `[1:2] prefix/postfix operator "~" do not support operand 'true' [bool]`}, + /* 17 */ {`~true`, nil, `[1:2] prefix/postfix operator "~" does not support operand 'true' [bool]`}, /* 18 */ {`1^2`, int64(3), nil}, /* 19 */ {`3^2`, int64(1), nil}, /* 20 */ {`a=1; a^=2`, int64(3), nil}, /* 21 */ {`a=1; ++a`, int64(2), nil}, /* 22 */ {`a=1; --a`, int64(0), nil}, - /* 23 */ {`[1,2,3] map var("_")`, newList([]any{int64(1), int64(2), int64(3)}), nil}, - /* 24 */ {`[1,2,3] map $_`, newList([]any{int64(1), int64(2), int64(3)}), nil}, - /* 25 */ {`[1,2,3,4] filter ($_ % 2 == 0)`, newList([]any{int64(2), int64(4)}), nil}, + /* 23 */ {`[1,2,3] map var("_")`, kern.NewList([]any{int64(1), int64(2), int64(3)}), nil}, + /* 24 */ {`[1,2,3] map $_`, kern.NewList([]any{int64(1), int64(2), int64(3)}), nil}, + /* 25 */ {`[1,2,3,4] filter ($_ % 2 == 0)`, kern.NewList([]any{int64(2), int64(4)}), nil}, /* 26 */ {`max=0; [2,3,1] digest max=(($_ > max) ? {$_} :: {max})`, int64(3), nil}, - /* 27 */ {`["a","b"] join ["x"]`, newList([]any{"a", "b", "x"}), nil}, + /* 27 */ {`["a","b"] join ["x"]`, kern.NewList([]any{"a", "b", "x"}), nil}, /* 28 */ {`["a","b"] join ["x"-true]`, nil, `[1:21] left operand 'x' [string] and right operand 'true' [bool] are not compatible with operator "-"`}, } diff --git a/t_parser_test.go b/t_parser_test.go index 778286f..d56fac1 100644 --- a/t_parser_test.go +++ b/t_parser_test.go @@ -6,6 +6,8 @@ package expr import ( "testing" + + "git.portale-stac.it/go-pkg/expr/kern" ) func TestGeneralParser(t *testing.T) { @@ -49,7 +51,7 @@ func TestGeneralParser(t *testing.T) { /* 35 */ {`var2="abc"; "uno_" + var2`, `uno_abc`, nil}, /* 36 */ {`0 || 0.0 && "hello"`, false, nil}, /* 37 */ {`"s" + true`, nil, `[1:6] left operand 's' [string] and right operand 'true' [bool] are not compatible with operator "+"`}, - /* 38 */ {`+false`, nil, `[1:2] prefix/postfix operator "+" do not support operand 'false' [bool]`}, + /* 38 */ {`+false`, nil, `[1:2] prefix/postfix operator "+" does not support operand 'false' [bool]`}, /* 39 */ {`false // very simple expression`, false, nil}, /* 40 */ {`1 + // Missing right operator`, nil, `[1:4] infix operator "+" requires two non-nil operands, got 1`}, /* 41 */ {"", nil, nil}, @@ -130,11 +132,11 @@ func TestGeneralParser(t *testing.T) { /* 116 */ {`null`, nil, `undefined variable or function "null"`}, /* 117 */ {`{"key"}`, nil, "[1:8] expected `:`, got `}`"}, /* 118 */ {`{"key":}`, nil, "[1:9] expected `dictionary-value`, got `}`"}, - /* 119 */ {`{}`, &DictType{}, nil}, + /* 119 */ {`{}`, &kern.DictType{}, nil}, /* 120 */ {`v=10; v++; v`, int64(11), nil}, - /* 121 */ {`1.2()`, newFraction(6, 5), nil}, + /* 121 */ {`1.2()`, kern.NewFraction(6, 5), nil}, /* 122 */ {`x="abc"; x ?! #x`, int64(3), nil}, - /* 123 */ {`x ?! #x`, nil, `[1:7] prefix/postfix operator "#" do not support operand '' [nil]`}, + /* 123 */ {`x ?! #x`, nil, `[1:7] prefix/postfix operator "#" does not support operand '' [nil]`}, /* 124 */ {`x ?! (x+1)`, nil, nil}, /* 125 */ {`"abx" ?! (x+1)`, nil, `[1:6] left operand of "?!" must be a variable`}, /* 126 */ {`"abx" ?? "pqr"`, nil, `[1:6] left operand of "??" must be a variable`}, diff --git a/t_scanner_test.go b/t_scanner_test.go index d4ce9cf..748b944 100644 --- a/t_scanner_test.go +++ b/t_scanner_test.go @@ -9,6 +9,8 @@ import ( "reflect" "strings" "testing" + + "git.portale-stac.it/go-pkg/expr/kern" ) func TestScanner(t *testing.T) { @@ -60,7 +62,7 @@ func TestScanner(t *testing.T) { /* 38 */ {`\`, SymError, errors.New("incomplete escape sequence"), nil}, /* 39 */ {`"string"`, SymString, "string", nil}, /* 40 */ {`identifier`, SymIdentifier, "identifier", nil}, - /* 41 */ {`1.2(3)`, SymFraction, newFraction(37, 30), nil}, + /* 41 */ {`1.2(3)`, SymFraction, kern.NewFraction(37, 30), nil}, } for i, input := range inputs { diff --git a/t_simple-store_test.go b/t_simple-store_test.go new file mode 100644 index 0000000..5d8eb06 --- /dev/null +++ b/t_simple-store_test.go @@ -0,0 +1,19 @@ +// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// t_simple-store_test.go +package expr + +import ( + "testing" +) + +func TestGetVar(t *testing.T) { + ctx := NewSimpleStoreWithoutGlobalContext() + ctx.SetVar("x", 10) + if value, exists := ctx.GetVar("x"); !exists { + t.Errorf("missing variable 'x'") + } else if value != int64(10) { + t.Errorf("expcted 10, got %v", value) + } +} diff --git a/t_strings_test.go b/t_strings_test.go index 52042ec..d8493d6 100644 --- a/t_strings_test.go +++ b/t_strings_test.go @@ -6,6 +6,8 @@ package expr import ( "testing" + + "git.portale-stac.it/go-pkg/expr/kern" ) func TestStringsParser(t *testing.T) { @@ -17,9 +19,9 @@ func TestStringsParser(t *testing.T) { /* 4 */ {`"uno" * (2+1)`, `unounouno`, nil}, /* 5 */ {`"abc"[1]`, `b`, nil}, /* 6 */ {`#"abc"`, int64(3), nil}, - /* 7 */ {`"192.168.0.240" / "."`, newListA("192", "168", "0", "240"), nil}, + /* 7 */ {`"192.168.0.240" / "."`, kern.NewListA("192", "168", "0", "240"), nil}, /* 8 */ {`("192.168.0.240" / ".")[1]`, "168", nil}, - /* 9 */ {`"AF3B0Dz" / 2`, newListA("AF", "3B", "0D", "z"), nil}, + /* 9 */ {`"AF3B0Dz" / 2`, kern.NewListA("AF", "3B", "0D", "z"), nil}, /* 10 */ {`"AF3B0Dz" / 0`, nil, "[1:12] division by zero"}, } diff --git a/t_term_test.go b/t_term_test.go index 9089ca6..0c22a85 100644 --- a/t_term_test.go +++ b/t_term_test.go @@ -37,7 +37,7 @@ func TestGetChildrenCount(t *testing.T) { tree := NewAst() if gotErr := tree.addTokens(tk1); gotErr == nil { - t.Log("Tree-root children count:", tree.root.getChildrenCount()) + t.Log("Tree-root children count:", tree.root.GetChildCount()) } else { t.Errorf("err: got <%v>, want ", gotErr) } diff --git a/t_utils-unix_test.go b/t_utils-unix_test.go index 4c166b9..75639e6 100644 --- a/t_utils-unix_test.go +++ b/t_utils-unix_test.go @@ -11,6 +11,8 @@ import ( "os/user" "path" "testing" + + "git.portale-stac.it/go-pkg/expr/kern" ) func TestExpandPathRootOk(t *testing.T) { @@ -19,7 +21,7 @@ func TestExpandPathRootOk(t *testing.T) { // wantErr := errors.New(`test expected string, got list ([])`) wantErr := error(nil) - gotValue, gotErr := ExpandPath(source) + gotValue, gotErr := kern.ExpandPath(source) if gotErr != nil && gotErr.Error() != wantErr.Error() { t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`, @@ -36,7 +38,7 @@ func TestExpandPathRootSubDirOk(t *testing.T) { // wantErr := errors.New(`test expected string, got list ([])`) wantErr := error(nil) - gotValue, gotErr := ExpandPath(source) + gotValue, gotErr := kern.ExpandPath(source) if gotErr != nil && gotErr.Error() != wantErr.Error() { t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`, @@ -54,7 +56,7 @@ func TestExpandPathUser(t *testing.T) { // wantErr := errors.New(`test expected string, got list ([])`) wantErr := error(nil) - gotValue, gotErr := ExpandPath(source) + gotValue, gotErr := kern.ExpandPath(source) if gotErr != nil { t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`, @@ -72,7 +74,7 @@ func TestExpandPathEnv(t *testing.T) { // wantErr := errors.New(`test expected string, got list ([])`) wantErr := error(nil) - gotValue, gotErr := ExpandPath(source) + gotValue, gotErr := kern.ExpandPath(source) if gotErr != nil { t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`, @@ -88,7 +90,7 @@ func TestExpandPathErr(t *testing.T) { wantValue := "~fake-user/test" wantErr := errors.New(`user: unknown user fake-user`) - gotValue, gotErr := ExpandPath(source) + gotValue, gotErr := kern.ExpandPath(source) if gotErr != nil && gotErr.Error() != wantErr.Error() { t.Errorf(`ExpandPath(%v) gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`, @@ -106,7 +108,7 @@ func TestExpandPathUserErr(t *testing.T) { // wantErr := errors.New(`test expected string, got list ([])`) wantErr := error(nil) - gotValue, gotErr := ExpandPath(source) + gotValue, gotErr := kern.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 cf496cb..79dd4dd 100644 --- a/t_utils_test.go +++ b/t_utils_test.go @@ -8,6 +8,8 @@ import ( "errors" "reflect" "testing" + + "git.portale-stac.it/go-pkg/expr/kern" ) func TestIsString(t *testing.T) { @@ -16,7 +18,7 @@ func TestIsString(t *testing.T) { failed := 0 count++ - if !IsBool(true) { + if !kern.IsBool(true) { t.Errorf("%d: IsBool(true) -> result = false, want true", count) failed++ } else { @@ -24,7 +26,7 @@ func TestIsString(t *testing.T) { } count++ - if !IsString("abc") { + if !kern.IsString("abc") { t.Errorf("%d: IsString(\"abc\") -> result = false, want true", count) failed++ } else { @@ -32,7 +34,7 @@ func TestIsString(t *testing.T) { } count++ - if !IsInteger(int64(123)) { + if !kern.IsInteger(int64(123)) { t.Errorf("%d: IsInteger(123) -> result = false, want true", count) failed++ } else { @@ -40,7 +42,7 @@ func TestIsString(t *testing.T) { } count++ - if !IsFloat(1.23) { + if !kern.IsFloat(1.23) { t.Errorf("%d: IsFloat(1.23) -> result = false, want true", count) failed++ } else { @@ -48,7 +50,7 @@ func TestIsString(t *testing.T) { } count++ - if !IsFloat(numAsFloat(123)) { + if !kern.IsFloat(kern.NumAsFloat(123)) { t.Errorf("%d: IsFloat(numAsFloat(123)) -> result = false, want true", count) failed++ } else { @@ -56,7 +58,7 @@ func TestIsString(t *testing.T) { } count++ - if isIterator("fake") { + if kern.IsIterator("fake") { t.Errorf(`%d: isIterator("fake") -> result = true, want false`, count) failed++ } else { @@ -64,7 +66,7 @@ func TestIsString(t *testing.T) { } count++ - b, ok := ToBool(true) + b, ok := kern.ToBool(true) if !(ok && b) { t.Errorf("%d: toBool(true) b=%v, ok=%v -> result = false, want true", count, b, ok) failed++ @@ -73,7 +75,7 @@ func TestIsString(t *testing.T) { } count++ - b, ok = ToBool("abc") + b, ok = kern.ToBool("abc") if !(ok && b) { t.Errorf("%d: toBool(\"abc\") b=%v, ok=%v -> result = false, want true", count, b, ok) failed++ @@ -82,7 +84,7 @@ func TestIsString(t *testing.T) { } count++ - b, ok = ToBool([]int{}) + b, ok = kern.ToBool([]int{}) if ok { t.Errorf("%d: toBool([]) b=%v, ok=%v -> result = true, want false", count, b, ok) failed++ @@ -98,7 +100,7 @@ func TestToIntOk(t *testing.T) { wantValue := int(64) wantErr := error(nil) - gotValue, gotErr := ToGoInt(source, "test") + gotValue, gotErr := kern.ToGoInt(source, "test") if gotErr != nil || gotValue != wantValue { t.Errorf("toInt(%v, \"test\") gotValue=%v, gotErr=%v -> wantValue=%v, wantErr=%v", @@ -111,7 +113,7 @@ func TestToIntErr(t *testing.T) { wantValue := 0 wantErr := errors.New(`test expected integer, got uint64 (64)`) - gotValue, gotErr := ToGoInt(source, "test") + gotValue, gotErr := kern.ToGoInt(source, "test") if gotErr.Error() != wantErr.Error() || gotValue != wantValue { t.Errorf("toInt(%v, \"test\") gotValue=%v, gotErr=%v -> wantValue=%v, wantErr=%v", @@ -144,7 +146,7 @@ func TestAnyInteger(t *testing.T) { failed := 0 for i, input := range inputs { - gotValue, gotOk := anyInteger(input.source) + gotValue, gotOk := kern.AnyInteger(input.source) if gotOk != input.wantOk || gotValue != input.wantValue { t.Errorf("%d: anyInteger(%v) -> gotOk = %t, wantOk = %t; gotValue = %v, wantValue = %v", i+1, input.source, gotOk, input.wantOk, gotValue, input.wantValue) @@ -159,7 +161,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 := CopyMap(dest, source) + result := kern.CopyMap(dest, source) if !reflect.DeepEqual(result, source) { t.Errorf("utils.CopyMap() failed") } @@ -170,7 +172,7 @@ func TestToStringOk(t *testing.T) { wantValue := "ciao" wantErr := error(nil) - gotValue, gotErr := ToGoString(source, "test") + gotValue, gotErr := kern.ToGoString(source, "test") if gotErr != nil { t.Error(gotErr) @@ -181,11 +183,11 @@ func TestToStringOk(t *testing.T) { } func TestToStringErr(t *testing.T) { - source := newListA() + source := kern.NewListA() wantValue := "" wantErr := errors.New(`test expected string, got list ([])`) - gotValue, gotErr := ToGoString(source, "test") + gotValue, gotErr := kern.ToGoString(source, "test") if gotErr != nil && gotErr.Error() != wantErr.Error() { t.Errorf(`ToGoString(%v, "test") gotValue=%q, gotErr=%v -> wantValue=%q, wantErr=%v`, @@ -197,15 +199,15 @@ func TestToStringErr(t *testing.T) { } func TestIsFunctorSucc(t *testing.T) { - f := NewGolangFunctor(isNilFunc) - if !isFunctor(f) { + f := kern.NewGolangFunctor(isNilFunc) + if !kern.IsFunctor(f) { t.Errorf("isNilFunc() evalued as not a functor") } } func TestIsFunctorFail(t *testing.T) { f := int64(1) - if isFunctor(f) { + if kern.IsFunctor(f) { t.Errorf("int evalued as a functor") } } diff --git a/term.go b/term.go index fc2c13d..e345bfc 100644 --- a/term.go +++ b/term.go @@ -6,6 +6,8 @@ package expr import ( "strings" + + "git.portale-stac.it/go-pkg/expr/kern" ) type termPriority uint32 @@ -49,7 +51,7 @@ const ( posMultifix ) -type evalFuncType func(ctx ExprContext, self *term) (v any, err error) +type evalFuncType func(ctx kern.ExprContext, self *term) (v any, err error) type term struct { tk Token @@ -60,40 +62,40 @@ type term struct { evalFunc evalFuncType } -func (s *term) Clone() (d *term) { +func (t *term) Clone() (d *term) { var children []*term - if s.children != nil { - children = make([]*term, len(s.children)) - for i, c := range s.children { + if t.children != nil { + children = make([]*term, len(t.children)) + for i, c := range t.children { children[i] = c.Clone() } } d = &term{ - tk: *s.tk.Clone(), - parent: s.parent, + tk: *t.tk.Clone(), + parent: t.parent, children: children, - position: s.position, - priority: s.priority, - evalFunc: s.evalFunc, + position: t.position, + priority: t.priority, + evalFunc: t.evalFunc, } return } -func (term *term) String() string { +func (t *term) String() string { var sb strings.Builder - term.toString(&sb) + t.toString(&sb) return sb.String() } -func (term *term) toString(sb *strings.Builder) { - if term.position == posLeaf { - sb.WriteString(term.tk.String()) +func (t *term) toString(sb *strings.Builder) { + if t.position == posLeaf { + sb.WriteString(t.tk.String()) } else { sb.WriteByte('[') - sb.WriteString(term.tk.String()) - if term.children != nil { + sb.WriteString(t.tk.String()) + if t.children != nil { sb.WriteByte('(') - for i, c := range term.children { + for i, c := range t.children { if i > 0 { sb.WriteByte(' ') } @@ -105,17 +107,17 @@ func (term *term) toString(sb *strings.Builder) { } } -func (term *term) getChildrenCount() (count int) { - if term.position == posLeaf || term.children == nil { +func (t *term) GetChildCount() (count int) { + if t.position == posLeaf || t.children == nil { count = 0 } else { - count = len(term.children) + count = len(t.children) } return } -func (term *term) getRoom() (room int) { - switch term.position { +func (t *term) getRoom() (room int) { + switch t.position { case posLeaf: room = 0 case posInfix: @@ -128,52 +130,70 @@ func (term *term) getRoom() (room int) { return } -func (term *term) isComplete() bool { - return term.getChildrenCount() == term.getRoom() +func (t *term) isComplete() bool { + return t.GetChildCount() == t.getRoom() } -func (term *term) removeLastChild() (child *term) { - if term.children != nil { - child = term.children[len(term.children)-1] - term.children = term.children[0 : len(term.children)-1] +func (t *term) removeLastChild() (child *term) { + if t.children != nil { + child = t.children[len(t.children)-1] + t.children = t.children[0 : len(t.children)-1] } else { panic("Can't get last child") } return } -func (term *term) isLeaf() bool { - return term.position == posLeaf +func (t *term) isLeaf() bool { + return t.position == posLeaf } -func (term *term) getPriority() termPriority { - return term.priority +func (t *term) getPriority() termPriority { + return t.priority } -func (term *term) setParent(parent *term) { - term.parent = parent +func (t *term) setParent(parent *term) { + t.parent = parent if parent != nil && len(parent.children) < cap(parent.children) { - parent.children = append(parent.children, term) + parent.children = append(parent.children, t) } } -func (term *term) symbol() Symbol { - return term.tk.Sym +func (t *term) symbol() Symbol { + return t.tk.Sym } -func (term *term) source() string { - return term.tk.source +func (t *term) Source() string { + return t.tk.source } -func (term *term) value() any { - return term.tk.Value +func (t *term) value() any { + return t.tk.Value } -func (term *term) compute(ctx ExprContext) (v any, err error) { - if term.evalFunc == nil { - err = term.Errorf("undefined eval-func for %q term", term.source()) +func (t *term) GetChild(index int) (c kern.Term) { + if index >= 0 && index < len(t.children) { + c = t.children[index] + } + return +} + +func (t *term) GetChildSource(index int) (s string) { + if index >= 0 && index < len(t.children) { + s = t.children[index].tk.source + } + return +} + +func (t *term) IsAssign() bool { + return t.symbol() == SymEqual +} + +func (t *term) Compute(ctx kern.ExprContext) (v any, err error) { + if t.evalFunc == nil { + err = t.Errorf("undefined eval-func for %q term", t.Source()) } else { - v, err = term.evalFunc(ctx, term) + v, err = t.evalFunc(ctx, t) } return } @@ -187,75 +207,81 @@ func (term *term) compute(ctx ExprContext) (v any, err error) { // return // } -func (term *term) errIncompatibleTypes(leftValue, rightValue any) error { - leftType := TypeName(leftValue) - leftText := getFormatted(leftValue, Truncate) - rightType := TypeName(rightValue) - rightText := getFormatted(rightValue, Truncate) - return term.tk.Errorf( +func (t *term) errIncompatibleTypes(leftValue, rightValue any) error { + leftType := kern.TypeName(leftValue) + leftText := kern.GetFormatted(leftValue, kern.Truncate) + rightType := kern.TypeName(rightValue) + rightText := kern.GetFormatted(rightValue, kern.Truncate) + return t.tk.Errorf( "left operand '%s' [%s] and right operand '%s' [%s] are not compatible with operator %q", leftText, leftType, rightText, rightType, - term.source()) + t.Source()) } -func (term *term) errIncompatibleType(value any) error { - return term.tk.Errorf( - "prefix/postfix operator %q do not support operand '%v' [%s]", - term.source(), value, TypeName(value)) +func (t *term) errIncompatibleType(value any, side string) error { + return t.tk.Errorf( + "operator %q does not support operand '%v' [%s] on its %s side", + t.Source(), value, kern.TypeName(value), side) } -func (term *term) errDivisionByZero() error { - return term.tk.Errorf("division by zero") +func (t *term) errIncompatiblePrefixPostfixType(value any) error { + return t.tk.Errorf( + "prefix/postfix operator %q does not support operand '%v' [%s]", + t.Source(), value, kern.TypeName(value)) } -func (term *term) Errorf(template string, args ...any) (err error) { - err = term.tk.Errorf(template, args...) +func (t *term) errDivisionByZero() error { + return t.tk.Errorf("division by zero") +} + +func (t *term) Errorf(template string, args ...any) (err error) { + err = t.tk.Errorf(template, args...) return } -func (term *term) checkOperands() (err error) { - switch term.position { +func (t *term) checkOperands() (err error) { + switch t.position { case posInfix: - if term.children == nil || len(term.children) != 2 || term.anyChildrenNil() { - err = term.tk.Errorf("infix operator %q requires two non-nil operands, got %d", term.source(), term.getChildrenCount()) + if t.children == nil || len(t.children) != 2 || t.anyChildrenNil() { + err = t.tk.Errorf("infix operator %q requires two non-nil operands, got %d", t.Source(), t.GetChildCount()) } case posPrefix: - if term.children == nil || len(term.children) != 1 || term.children[0] == nil { - err = term.tk.Errorf("prefix operator %q requires one non-nil operand", term.tk.String()) + if t.children == nil || len(t.children) != 1 || t.children[0] == nil { + err = t.tk.Errorf("prefix operator %q requires one non-nil operand", t.tk.String()) } case posPostfix: - if term.children == nil || len(term.children) != 1 || term.anyChildrenNil() { - err = term.tk.Errorf("postfix operator %q requires one non-nil operand", term.tk.String()) + if t.children == nil || len(t.children) != 1 || t.anyChildrenNil() { + err = t.tk.Errorf("postfix operator %q requires one non-nil operand", t.tk.String()) } case posMultifix: - if term.children == nil || len(term.children) < 3 || term.anyChildrenNil() { - err = term.tk.Errorf("infix operator %q requires at least three not operands, got %d", term.source(), term.getChildrenCount()) + if t.children == nil || len(t.children) < 3 || t.anyChildrenNil() { + err = t.tk.Errorf("infix operator %q requires at least three not operands, got %d", t.Source(), t.GetChildCount()) } } return } -func (term *term) anyChildrenNil() bool { - for _, child := range term.children { +func (t *term) anyChildrenNil() bool { + for _, child := range t.children { if child == nil { return true } } return false } -func (term *term) evalInfix(ctx ExprContext) (leftValue, rightValue any, err error) { - if err = term.checkOperands(); err == nil { - if leftValue, err = term.children[0].compute(ctx); err == nil { - rightValue, err = term.children[1].compute(ctx) +func (t *term) evalInfix(ctx kern.ExprContext) (leftValue, rightValue any, err error) { + if err = t.checkOperands(); err == nil { + if leftValue, err = t.children[0].Compute(ctx); err == nil { + rightValue, err = t.children[1].Compute(ctx) } } return } -func (term *term) evalPrefix(ctx ExprContext) (childValue any, err error) { - if err = term.checkOperands(); err == nil { - childValue, err = term.children[0].compute(ctx) +func (t *term) evalPrefix(ctx kern.ExprContext) (childValue any, err error) { + if err = t.checkOperands(); err == nil { + childValue, err = t.children[0].Compute(ctx) } return }