From f198ba47e1ff91ea15fe83728bde50f444098db3 Mon Sep 17 00:00:00 2001 From: Celestino Amoroso Date: Sat, 20 Apr 2024 07:29:42 +0200 Subject: [PATCH] new convert function int() --- func-builtins.go | 33 ++++++++++++++++++-- func-common.go | 17 ++++++++++ funcs_test.go | 80 ++++++++++++++++++++++++++++++++++++++++++++++++ parser_test.go | 3 -- 4 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 func-common.go create mode 100644 funcs_test.go diff --git a/func-builtins.go b/func-builtins.go index ad574b8..6b77c3b 100644 --- a/func-builtins.go +++ b/func-builtins.go @@ -5,20 +5,49 @@ package expr import ( - "fmt" + "math" + "strconv" ) func isNilFunc(ctx ExprContext, name string, args []any) (result any, err error) { if len(args) == 1 { result = args[0] == nil } else { - err = fmt.Errorf("%s() requires exactly one param", name) + err = errOneParam(name) + } + return +} + +func intFunc(ctx ExprContext, name string, args []any) (result any, err error) { + if len(args) == 1 { + switch v := args[0].(type) { + case int64: + result = v + case float64: + result = int64(math.Trunc(v)) + case bool: + if v { + result = int64(1) + } else { + result = int64(0) + } + case string: + var i int + if i, err = strconv.Atoi(v); err == nil { + result = int64(i) + } + default: + err = errCantConvert(name, v, "int") + } + } else { + err = errOneParam(name) } return } func ImportBuiltinsFuncs(ctx ExprContext) { ctx.RegisterFunc("isNil", &simpleFunctor{f: isNilFunc}, 1, -1) + ctx.RegisterFunc("int", &simpleFunctor{f: intFunc}, 1, -1) } func init() { diff --git a/func-common.go b/func-common.go new file mode 100644 index 0000000..1c6d3a4 --- /dev/null +++ b/func-common.go @@ -0,0 +1,17 @@ +// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// func-common.go +package expr + +import ( + "fmt" +) + +func errOneParam(funcName string) error { + return fmt.Errorf("%s() requires exactly one param", funcName) +} + +func errCantConvert(funcName string, value any, kind string) error { + return fmt.Errorf("%s() can't convert %T to %s", funcName, value, kind) +} diff --git a/funcs_test.go b/funcs_test.go new file mode 100644 index 0000000..d2851c0 --- /dev/null +++ b/funcs_test.go @@ -0,0 +1,80 @@ +// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com). +// All rights reserved. + +// funcs_test.go +package expr + +import ( + "errors" + "fmt" + "strings" + "testing" +) + +func TestFuncs(t *testing.T) { + type inputType struct { + source string + wantResult any + wantErr error + } + + inputs := []inputType{ + /* 1 */ {`isNil(nil)`, true, nil}, + /* 2 */ {`v=nil; isNil(v)`, true, nil}, + /* 3 */ {`v=5; isNil(v)`, false, nil}, + /* 4 */ {`int(true)`, int64(1), nil}, + /* 5 */ {`int(false)`, int64(0), nil}, + /* 6 */ {`int(3.1)`, int64(3), nil}, + /* 7 */ {`int(3.9)`, int64(3), nil}, + /* 8 */ {`int("432")`, int64(432), nil}, + /* 9 */ {`int("1.5")`, nil, errors.New(`strconv.Atoi: parsing "1.5": invalid syntax`)}, + } + + succeeded := 0 + failed := 0 + + // inputs1 := []inputType{ + // /* 1 */ {`0?{}`, nil, nil}, + // } + + for i, input := range inputs { + var expr Expr + var gotResult any + var gotErr error + + ctx := NewSimpleFuncStore() + // ImportMathFuncs(ctx) + // ImportImportFunc(ctx) + // ImportOsFuncs(ctx) + parser := NewParser(ctx) + + logTest(t, i+1, input.source, input.wantResult, input.wantErr) + + r := strings.NewReader(input.source) + scanner := NewScanner(r, DefaultTranslations()) + + good := true + if expr, gotErr = parser.Parse(scanner); gotErr == nil { + gotResult, gotErr = expr.Eval(ctx) + } + + if gotResult != input.wantResult { + t.Errorf("%d: %q -> result = %v [%T], want %v [%T]", i+1, input.source, gotResult, gotResult, input.wantResult, input.wantResult) + good = false + } + + if gotErr != input.wantErr { + if input.wantErr == nil || gotErr == nil || (gotErr.Error() != input.wantErr.Error()) { + t.Errorf("%d: %q -> err = <%v>, want <%v>", i+1, input.source, gotErr, input.wantErr) + good = false + } + } + + if good { + succeeded++ + } else { + failed++ + } + } + t.Log(fmt.Sprintf("test count: %d, succeeded count: %d, failed count: %d", len(inputs), succeeded, failed)) +} diff --git a/parser_test.go b/parser_test.go index 30e22a8..0c5d053 100644 --- a/parser_test.go +++ b/parser_test.go @@ -158,9 +158,6 @@ func TestParser(t *testing.T) { /* 137 */ {`2 + 1 ? {"a"} : {"b"} * 3`, "2bbb", nil}, /* 138 */ {`nil`, nil, nil}, /* 139 */ {`null`, nil, errors.New(`undefined variable "null"`)}, - /* 140 */ {`isNil(nil)`, true, nil}, - /* 141 */ {`v=nil; isNil(v)`, true, nil}, - /* 142 */ {`v=5; isNil(v)`, false, nil}, } check_env_expr_path := 113