Skip to content

Commit

Permalink
replace parser pkg
Browse files Browse the repository at this point in the history
  • Loading branch information
710leo committed Feb 20, 2024
1 parent cdc2d4c commit e78e212
Show file tree
Hide file tree
Showing 7 changed files with 462 additions and 1,206 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/expr-lang/expr v1.16.1
github.com/gin-contrib/pprof v1.4.0
github.com/gin-gonic/gin v1.9.1
github.com/go-ldap/ldap/v3 v3.4.4
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumC
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/expr-lang/expr v1.16.1 h1:Na8CUcMdyGbnNpShY7kzcHCU7WqxuL+hnxgHZ4vaz/A=
github.com/expr-lang/expr v1.16.1/go.mod h1:uCkhfG+x7fcZ5A5sXHKuQ07jGZRl6J0FCAaf2k4PtVQ=
github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
Expand Down
60 changes: 0 additions & 60 deletions pkg/parser/ast.go

This file was deleted.

208 changes: 32 additions & 176 deletions pkg/parser/calc.go
Original file line number Diff line number Diff line change
@@ -1,203 +1,59 @@
package parser

import (
"fmt"
"strconv"
"regexp"
"strings"

"github.com/expr-lang/expr"
"github.com/toolkits/pkg/logger"
)

func MathCalc(s string, data map[string]float64) (float64, error) {
var err error
p := NewParser([]rune(s))
err = p.Parse()
if err != nil {
return 0, err
}

for _, stat := range p.Stats() {
v, err := eval(stat, data)
if err != nil {
return 0, err
}
logger.Infof("exp:%s res:%v", s, v)
return v, nil
}

return 0, err
}

func Calc(s string, data map[string]float64) bool {
var err error
p := NewParser([]rune(s))
err = p.Parse()
if err != nil {
logger.Errorf("parse err:%v", err)
return false
}

for _, stat := range p.Stats() {
v, err := eval(stat, data)
if err != nil {
logger.Error("eval error:", err)
return false
}
logger.Infof("exp:%s res:%v", s, v)
if v > 0.0 {
return true
}
}

return false
}

func eval(stat Node, data map[string]float64) (float64, error) {
switch node := stat.(type) {
case *BinaryNode:
return evalBinary(node, data)
case *IdentifierNode:
return get(node.Lit, data)
case *NumberNode:
return evaluateNumber(node)
default:
return 0, fmt.Errorf("invalid node: %v", node)
m := make(map[string]float64)
for k, v := range data {
m[cleanStr(k)] = v
}
}

func evaluateNumber(node *NumberNode) (float64, error) {
switch node.Type {
case IntLiteral:
v, err := strconv.ParseFloat(node.Lit, 64)
if err != nil {
return 0, err
}
return v, nil
}
return 0, fmt.Errorf("invalid type: %v", node.Type)
}

func get(name string, data map[string]float64) (float64, error) {
value, exists := data[name]
if !exists {
return 0, fmt.Errorf("%s not found", name)
}

return value, nil
}

func evalBinary(node *BinaryNode, data map[string]float64) (float64, error) {
left, err := eval(node.Left, data)
program, err := expr.Compile(cleanStr(s), expr.Env(m))
if err != nil {
return 0, err
}
right, err := eval(node.Right, data)

output, err := expr.Run(program, m)
if err != nil {
return 0, err
}

switch node.Type {
case AND:
return and(left, right), nil
case OR:
return or(left, right), nil
case Plus:
return add(left, right), nil
case Minus:
return minus(left, right), nil
case Star:
return star(left, right), nil
case Slash:
return slash(left, right)
case GT:
return gt(left, right), nil
case GE:
return ge(left, right), nil
case LT:
return lt(left, right), nil
case LE:
return le(left, right), nil
case EQ:
return eq(left, right), nil
case NE:
return ne(left, right), nil
}
return 0, fmt.Errorf("invalid operator: %v", node.Type)
}

// and
func and(left, right float64) float64 {
if left > 0.0 && right > 0.0 {
return 1
}
return 0
}

// or
func or(left, right float64) float64 {
if left > 0.0 || right > 0.0 {
return 1
}
return 0
}

func gt(left, right float64) float64 {
if left > right {
return 1
}
return 0
}

func ge(left, right float64) float64 {
if left >= right {
return 1
}
return 0
}

func lt(left, right float64) float64 {
if left < right {
return 1
}
return 0
}

func le(left, right float64) float64 {
if left <= right {
return 1
}
return 0
}

func eq(left, right float64) float64 {
if left == right {
return 1
if result, ok := output.(float64); ok {
return result, nil
} else if result, ok := output.(bool); ok {
if result {
return 1, nil
} else {
return 0, nil
}
} else {
return 0, nil
}
return 0
}

func ne(left, right float64) float64 {
if left != right {
return 1
func Calc(s string, data map[string]float64) bool {
v, err := MathCalc(s, data)
if err != nil {
logger.Errorf("Calc exp:%s data:%v error: %v", s, data, err)
return false
}
return 0
}

func add(left, right float64) float64 {
return left + right
return v > 0
}

func minus(left, right float64) float64 {
return left - right
func cleanStr(s string) string {
s = replaceDollarSigns(s)
s = strings.ReplaceAll(s, "$.", "")
return s
}

func star(left, right float64) float64 {
return left * right
}

func slash(left, right float64) (float64, error) {
if right == 0 {
return 0, fmt.Errorf("right is zero")
}
res := left / right
return res, nil
func replaceDollarSigns(s string) string {
re := regexp.MustCompile(`\$([A-Z])\.`)
return re.ReplaceAllString(s, "${1}_")
}
Loading

0 comments on commit e78e212

Please sign in to comment.