Skip to content

Commit

Permalink
支持 可选参数自定义函数的注册
Browse files Browse the repository at this point in the history
  • Loading branch information
dengsgo committed Oct 23, 2021
1 parent 66c5260 commit 512f318
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 11 deletions.
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |

Expand Down Expand Up @@ -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
Expand All @@ -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

Expand Down
12 changes: 8 additions & 4 deletions engine/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
41 changes: 39 additions & 2 deletions engine/util_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package engine

import "testing"
import (
"math/rand"
"testing"
"time"
)

func TestParseAndExecSimple(t *testing.T) {
type U struct {
Expand Down Expand Up @@ -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)
}
}
Expand Down Expand Up @@ -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
}

0 comments on commit 512f318

Please sign in to comment.