From 512f31890db3c06b748c63a00e0896a3e43cdbb0 Mon Sep 17 00:00:00 2001 From: dengsgo Date: Sat, 23 Oct 2021 15:26:06 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=20=E5=8F=AF=E9=80=89?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E8=87=AA=E5=AE=9A=E4=B9=89=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E7=9A=84=E6=B3=A8=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 11 ++++++----- engine/util.go | 12 ++++++++---- engine/util_test.go | 41 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 53 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 8f857a2..8a34344 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,8 @@ | `round(x)` | 四舍五入取整 | round(4.4) = 4, round(4.5) = 5 | | `sqrt(x)` | 平方根,square root | sqrt(4) = 2 | | `cbrt(x)` | 立方根,cube root | cbrt(27) = 3 | -| `max(x, y)` | x, y 中的较大值 | max(2, 3) = 3 | -| `min(x, y)` | x, y 中的较小值 | min(2, 3) = 2 | +| `max(x, ...)` | 参数中的较大值 | max(1)=1,max(2,3)=3,max(4,8,6,8,10)=10 | +| `min(x, ...)` | 参数中的较小值 | min(1)=1,min(2,3)=2,max(4,8,6,8,10)=4 | | `noerr(x)` | 计算 x 出错时返回 0 | noerr(1 / 1) = 1, noerr( 1/ 0 ) = 0 | | `double(x)` | 返回 x 的双倍值,这是一个自定义的函数示例,你可以注册任意的自定义函数到引擎中 | double(6) = 12 | @@ -154,10 +154,10 @@ e.g // RegFunction is Top level function // the same function name only needs to be registered once. // double is register function name. - // 1 is a number of parameter signatures. + // 1 is a number of parameter signatures. should be -1, 0, or a positive integer // func(expr ...engine.ExprAST) float64 is your function. engine.RegFunction("double", 1, func(expr ...engine.ExprAST) float64 { - // you can use the index value directly according to the number of parameters + // when argc > 0,you can use the index value directly according to the number of parameters // without worrying about crossing the boundary. // use ExprASTResult to get the result of the ExprAST structure. return engine.ExprASTResult(expr[0]) * 2 @@ -178,7 +178,8 @@ fmt.Printf("double(6) + 2 = %f\n", r) // will print : double(6) + 2 = 14.00000 注意事项: - 注册的函数名只能是英文字母和数字,且必须英文字母开头(区分大小写); - 每一个函数名只能且只需注册一次; -- 注册的函数逻辑中如果有 panic ,需要程序自己捕获处理; +- 注册的函数逻辑中如果有 panic ,需要程序自己捕获处理; +- argc=-1,即该函数的参数是可变的,expr 的长度需要开发者自行逻辑判断处理; ## Compile diff --git a/engine/util.go b/engine/util.go index 3cc7e61..ded93eb 100644 --- a/engine/util.go +++ b/engine/util.go @@ -63,15 +63,19 @@ func Float64ToStr(f float64) string { // RegFunction is Top level function // register a new function to use in expressions +// name: be register function name. the same function name only needs to be registered once. +// argc: this is a number of parameter signatures. should be -1, 0, or a positive integer +// -1 variable-length argument; >=0 fixed numbers argument +// fun: function handler func RegFunction(name string, argc int, fun func(...ExprAST) float64) error { if len(name) == 0 { - return errors.New("RegFunction name is not empty.") + return errors.New("RegFunction name is not empty") } - if argc < 1 { - return errors.New("RegFunction argc is must has one arg at least.") + if argc < -1 { + return errors.New("RegFunction argc should be -1, 0, or a positive integer") } if _, ok := defFunc[name]; ok { - return errors.New("RegFunction name is already exist.") + return errors.New("RegFunction name is already exist") } defFunc[name] = defS{argc, fun} return nil diff --git a/engine/util_test.go b/engine/util_test.go index 9069503..e054124 100644 --- a/engine/util_test.go +++ b/engine/util_test.go @@ -1,6 +1,10 @@ package engine -import "testing" +import ( + "math/rand" + "testing" + "time" +) func TestParseAndExecSimple(t *testing.T) { type U struct { @@ -144,11 +148,35 @@ func TestRegFunction(t *testing.T) { "percentage50(6)", 3, }, + { + "range", + 0, + func(expr ...ExprAST) float64 { + return 10.0 + }, + "range()", + 10, + }, + { + "choice", + -1, + func(expr ...ExprAST) float64 { + rand.Seed(time.Now().UnixNano()) + return ExprASTResult(expr[rand.Intn(len(expr))]) + }, + "choice(1.1, 9.8, 2.5, 100)", + 10, + }, } for _, f := range funs { _ = RegFunction(f.Name, f.Argc, f.Fun) r, err := ParseAndExec(f.Exp) - if r != f.R { + if f.Name == "choice" { + if !inSlices(r, []float64{1.1, 9.8, 2.5, 100}) { + t.Error(err, "RegFunction errors when register new function: ", f.Name) + } + continue + } else if r != f.R { t.Error(err, "RegFunction errors when register new function: ", f.Name) } } @@ -194,3 +222,12 @@ func TestParseAndExecError(t *testing.T) { } } } + +func inSlices(target float64, s []float64) bool { + for _, v := range s { + if v == target { + return true + } + } + return false +}