package evaluate import ( "fmt" "go/ast" "go/parser" "go/token" "math" "regexp" "strconv" "strings" ) // Parse and caculate expression func CalcExpr(expr string, paramValues map[string]any) (float64, error) { // match parameter with '' re := regexp.MustCompile(`'([^']+)'`) matches := re.FindAllStringSubmatch(expr, -1) // replace to value for _, match := range matches { paramName := match[1] value, exists := paramValues[paramName] if !exists { return 0, fmt.Errorf("parameter '%s' not found", paramName) } expr = strings.Replace(expr, match[0], fmt.Sprintf("%v", value), 1) } // expression to evaluate result, err := evalExpr(expr) if math.IsNaN(result) { return 0.0, err } return result, err } // eval 解析和计算表达式 func evalExpr(expr string) (float64, error) { //fset := token.NewFileSet() node, err := parser.ParseExpr(expr) if err != nil { return 0, err } return evalNode(node) } // EvaluateExpr 解析并计算给定的表达式 func EvalExpr(expr string, values map[string]any) (float64, error) { // 解析表达式 node, err := parser.ParseExpr(expr) if err != nil { return 0, err } // 遍历 AST 并替换变量 ast.Inspect(node, func(n ast.Node) bool { if ident, ok := n.(*ast.Ident); ok { if val, ok := values[ident.Name]; ok { // 替换标识符为对应值 ident.Name = fmt.Sprintf("%v", val) } } return true }) // 计算表达式 return evalNode(node) } // eval 递归计算 AST 节点 func evalNode(node ast.Node) (float64, error) { var result float64 switch n := node.(type) { case *ast.BinaryExpr: left, err := evalNode(n.X) if err != nil { return 0, err } right, err := evalNode(n.Y) if err != nil { return 0, err } switch n.Op { case token.ADD: result = left + right case token.SUB: result = left - right case token.MUL: result = left * right case token.QUO: if right == 0 { return math.NaN(), fmt.Errorf("divisor cannot be zero") } result = left / right } case *ast.BasicLit: var err error result, err = strconv.ParseFloat(n.Value, 64) if err != nil { return 0, err } case *ast.Ident: val, err := strconv.ParseFloat(n.Name, 64) if err != nil { return 0, fmt.Errorf("unsupported expression: %s", n.Name) } result = val case *ast.ParenExpr: return evalNode(n.X) // 递归评估括号中的表达式 default: return 0, fmt.Errorf("unsupported expression: %T", n) } return result, nil }