From be5f750723474ff44ec43d9f4121ab7d0127e7a5 Mon Sep 17 00:00:00 2001 From: skyhackvip <369983954@qq.com> Date: Wed, 29 Nov 2023 16:03:50 +0800 Subject: [PATCH] evaluate bool expression --- core/common.go | 4 ++-- core/conditional.go | 4 ++-- internal/operator/logic.go | 32 ++++++++++++++++++++---------- internal/operator/operator_test.go | 19 ++++++++++++++++++ 4 files changed, 44 insertions(+), 15 deletions(-) diff --git a/core/common.go b/core/common.go index 50dfec0..35b0f73 100644 --- a/core/common.go +++ b/core/common.go @@ -45,7 +45,7 @@ func (rule *Rule) Parse(ctx *PipelineContext, depends map[string]IFeature) (outp return } - var conditionRet = make(map[string]interface{}, 0) + var conditionRet = make(map[string]bool, 0) for _, condition := range rule.Conditions { if feature, ok := depends[condition.Feature]; ok { rs, err := feature.Compare(condition.Operator, condition.Value) @@ -67,7 +67,7 @@ func (rule *Rule) Parse(ctx *PipelineContext, depends map[string]IFeature) (outp //rule.Decision expr := rule.Decision.Logic - logicRet, err := operator.Evaluate(expr, conditionRet) + logicRet, err := operator.EvaluateBoolExpr(expr, conditionRet) //某个表达式执行失败会导致最终逻辑执行失败 if err != nil { return diff --git a/core/conditional.go b/core/conditional.go index 3176853..55b530c 100644 --- a/core/conditional.go +++ b/core/conditional.go @@ -39,7 +39,7 @@ func (conditional ConditionalNode) Parse(ctx *PipelineContext) (*NodeResult, err depends := ctx.GetFeatures(info.Depends) var matchBranch bool for _, branch := range conditional.Branchs { //loop all the branch - var conditionRet = make(map[string]interface{}, 0) + var conditionRet = make(map[string]bool, 0) for _, condition := range branch.Conditions { if feature, ok := depends[condition.Feature]; ok { rs, err := feature.Compare(condition.Operator, condition.Value) @@ -55,7 +55,7 @@ func (conditional ConditionalNode) Parse(ctx *PipelineContext) (*NodeResult, err if len(conditionRet) == 0 { //current branch not match continue } - logicRs, err := operator.Evaluate(branch.Decision.Logic, conditionRet) + logicRs, err := operator.EvaluateBoolExpr(branch.Decision.Logic, conditionRet) if err != nil { continue } diff --git a/internal/operator/logic.go b/internal/operator/logic.go index 21998dc..c00cc0e 100644 --- a/internal/operator/logic.go +++ b/internal/operator/logic.go @@ -7,16 +7,12 @@ import ( // evaluate 计算逻辑表达式的值 func EvaluateBoolExpr(expr string, variables map[string]bool) (bool, error) { - expr = strings.ReplaceAll(expr, " ", "") // 去除空格 - if len(expr) == 0 { - return false, fmt.Errorf("empty expression") - } - if !isValid(expr) { - return false, fmt.Errorf("invalid expression") - } // 将表达式拆分成一个个token - tokens := splitExpression(expr) + tokens, err := splitExpression(expr) + if err != nil { + return false, err + } // 开始执行逻辑运算 stack := make([]bool, 0) @@ -126,7 +122,10 @@ func evaluateOp(b1, b2 bool, op string) bool { // isValid 检查表达式是否合法 func isValid(expr string) bool { - allowed := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!()+-*%/|&" + if len(expr) == 0 { + return false + } + allowed := "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!()+-_*%/|&," stack := make([]rune, 0) for _, ch := range expr { if ch == '(' { @@ -144,9 +143,14 @@ func isValid(expr string) bool { } // splitExpression 将表达式拆分为token -func splitExpression(expr string) []string { +func splitExpression(expr string) ([]string, error) { + expr = strings.ReplaceAll(expr, " ", "") // 去除空格 + if !isValid(expr) { + return nil, fmt.Errorf("invalid expression") + } tokens := make([]string, 0) buf := make([]rune, 0) + for i := 0; i < len(expr); i++ { ch := rune(expr[i]) if ch == '&' && i < len(expr)-1 && rune(expr[i+1]) == '&' { @@ -169,6 +173,12 @@ func splitExpression(expr string) []string { buf = []rune{} } tokens = append(tokens, string(ch)) + } else if ch == ',' { + if len(buf) > 0 { + tokens = append(tokens, string(buf)) + buf = []rune{} + } + tokens = append(tokens, string(ch)) } else { buf = append(buf, ch) } @@ -176,5 +186,5 @@ func splitExpression(expr string) []string { if len(buf) > 0 { tokens = append(tokens, string(buf)) } - return tokens + return tokens, nil } diff --git a/internal/operator/operator_test.go b/internal/operator/operator_test.go index 6a0edf1..df14848 100644 --- a/internal/operator/operator_test.go +++ b/internal/operator/operator_test.go @@ -56,3 +56,22 @@ func TestBoolExpr(t *testing.T) { t.Log(expr, result, err) t.Log(EvaluateBoolExpr("!(foo&&bar)||!a1", variables)) } + +func TestSplit(t *testing.T) { + //t.Log(splitExpression("max(foo,bar)")) + // t.Log(splitExpression("tmax(foo,bar)")) + // t.Log(splitExpression("!max(foo,bar)")) + variables := map[string]bool{ + "foo": true, + "bar": false, + } + t.Log(EvaluateExpr("max(foo,bar)", variables)) +} + +func TestEval(t *testing.T) { + variables := map[string]interface{}{ + "foo": 1, + "bar": 2, + } + t.Log(Evaluate("max(foo, bar)", variables)) +}