support aim walk

Change-Id: I9014e1edadd22fbeb17bf3d4473fed47b784134a
This commit is contained in:
murasame
2024-01-12 14:40:34 +08:00
parent ccf291b99c
commit b35808b0ca
4 changed files with 99 additions and 16 deletions

View File

@@ -19,6 +19,7 @@ package arishem
import (
"context"
"errors"
"github.com/antlr/antlr4/runtime/Go/antlr/v4"
"github.com/bytedance/arishem/internal/core"
"github.com/bytedance/arishem/tools"
"github.com/bytedance/arishem/typedef"
@@ -41,31 +42,65 @@ func DataContext(ctx context.Context, json string) (dc typedef.DataCtx, err erro
// ParseCondition will parse a condition string and return the rule tree with feature parameter pre-parsed.
func ParseCondition(condition string) (tree *RuleTree, err error) {
condition = strings.TrimSpace(condition)
if condition == "" {
err = errors.New("empty cond text")
return ParseRuleTree(condition, ExprTypeCondition)
}
// ParseAim will parse an aim string and return the rule tree with feature parameter pre-parsed.
func ParseAim(aim string) (tree *RuleTree, err error) {
return ParseRuleTree(aim, ExprTypeAim)
}
// ParseRuleTree will try parsing expr to antlr parse tree, err will not be null when failed.
func ParseRuleTree(expr string, exprType ExprType) (exprTree *RuleTree, err error) {
expr = strings.TrimSpace(expr)
if expr == "" {
err = errors.New("empty expression")
return
}
condition, err = tools.Compat(condition)
expr, err = tools.Compat(expr)
if err != nil {
return
}
var ok bool
tree, ok = arishemConfiguration.TCache.Get(condition)
if ok && tree != nil {
exprTree, ok = arishemConfiguration.TCache.Get(expr)
if ok && exprTree != nil {
return
}
tree, err = parseRuleTree(condition, exprTypeCondition)
exprTree, err = parseRuleTree(expr, exprType)
if err != nil {
return
}
if tree.Tree == nil {
if exprTree.Tree == nil {
err = errors.New("tree parsed is null")
return
}
return
}
// WalkAim will try to parse the aimExpr into the antlr parse tree and visit it to get the result, err will not be null when parse aim expression failed.
func WalkAim(aimExpr string, dc typedef.DataCtx, opts ...ExecuteOption) (aim typedef.Aim, err error) {
var tree *RuleTree
tree, err = ParseAim(aimExpr)
if err != nil {
return
}
rv := core.NewArishemRuleVisitor()
ApplyExecuteOptions(rv, dc, opts...)
if len(tree.FeatParams) > 0 {
dc.PrefetchFeatures(tree.FeatParams)
}
aim = rv.VisitAim(tree.Tree, dc, &dummyVisitTarget{name: aimExpr})
return
}
// WalkAimTree will visit the aimTree to get the result
func WalkAimTree(aimTree antlr.ParseTree, dc typedef.DataCtx, opts ...ExecuteOption) (aim typedef.Aim) {
rv := core.NewArishemRuleVisitor()
ApplyExecuteOptions(rv, dc, opts...)
aim = rv.VisitAim(aimTree, dc, &dummyVisitTarget{name: aimTree.GetText()})
return
}
// JudgeCondition will judge the condition string, pass will be set true if condition passed.
func JudgeCondition(ctx context.Context, condition string, opts ...ExecuteOption) (pass bool, err error) {
return JudgeConditionWithFactMeta(ctx, condition, "{}", opts...)

View File

@@ -297,3 +297,51 @@ func TestLWAPI(t *testing.T) {
case5()
case6()
}
func TestWalkAim(t *testing.T) {
testCases := []*struct {
aimExpr string
dcExpr string
check func(aim typedef.Aim, err error)
}{
{
`{
"Const": {
"StrConst": "p-rule3 passed!"
}
}`,
`{}`,
func(aim typedef.Aim, err error) {
fmt.Printf("%v\n", aim.AsExpr())
assert.NotNil(t, aim)
assert.Nil(t, err)
},
},
{
`{"MathExpr":{"OpMath":">","ParamList":[{"Const":{"NumConst":100}},{"Const":{"NumConst":20}}]}}`,
`{}`,
func(aim typedef.Aim, err error) {
assert.Nil(t, aim)
assert.NotNil(t, err)
fmt.Printf("%v\n", err)
},
},
{
`{"MapExpr":{"UserName":{"VarExpr":"user.username"},"UserAge":{"MathExpr":{"OpMath":"+","Lhs":{"Const":{"NumConst":10}},"Rhs":{"Const":{"NumConst":8}}}},"UserWeight":{"MathExpr":{"OpMath":"+","ParamList":[{"Const":{"NumConst":100}},{"Const":{"NumConst":20}}]}},"UserPersonality":{"FeatureExpr":{"FeaturePath":"user_center.user_personality","BuiltinParam":{"user_id":{"VarExpr":"user.id"}}}}}}`,
`{}`,
func(aim typedef.Aim, err error) {
assert.Nil(t, err)
assert.NotNil(t, aim)
fmt.Printf("%v\n", aim.AsExpr())
},
},
}
for _, testCase := range testCases {
dc, err := DataContext(context.Background(), testCase.dcExpr)
if err != nil {
testCase.check(nil, err)
continue
}
testCase.check(WalkAim(testCase.aimExpr, dc))
}
}

View File

@@ -45,11 +45,11 @@ type RuleResult interface {
Aim() typedef.Aim
}
type exprType int
type ExprType int
const (
exprTypeCondition = iota
exprTypeAim
ExprTypeCondition = iota
ExprTypeAim
)
type ruleResult struct {
@@ -183,7 +183,7 @@ func tryParse(cdtExpr, aimExpr string) (cdtTree, aimTree *RuleTree, err error) {
wg.Add(1)
arishemConfiguration.RuleComputePool.Submit(func(interface{}) {
defer wg.Done()
cdtTree, cdtErr = parseRuleTree(cdtExpr, exprTypeCondition)
cdtTree, cdtErr = parseRuleTree(cdtExpr, ExprTypeCondition)
}, nil)
}
@@ -197,7 +197,7 @@ func tryParse(cdtExpr, aimExpr string) (cdtTree, aimTree *RuleTree, err error) {
wg.Add(1)
arishemConfiguration.RuleComputePool.Submit(func(interface{}) {
defer wg.Done()
aimTree, aimErr = parseRuleTree(aimExpr, exprTypeAim)
aimTree, aimErr = parseRuleTree(aimExpr, ExprTypeAim)
}, nil)
}
// wait for parsing
@@ -223,11 +223,11 @@ func tryParse(cdtExpr, aimExpr string) (cdtTree, aimTree *RuleTree, err error) {
return
}
func parseRuleTree(exprStr string, expT exprType) (exprTree *RuleTree, err error) {
func parseRuleTree(exprStr string, expT ExprType) (exprTree *RuleTree, err error) {
fppl := core.NewFeaturePreParseListener()
var treeCtx antlr.ParseTree
if expT == exprTypeCondition {
if expT == ExprTypeCondition {
treeCtx, err = parser.ParseArishemCondition(exprStr, fppl)
} else {
treeCtx, err = parser.ParseArishemAim(exprStr, fppl)

View File

@@ -99,7 +99,7 @@ func (a *arishemRuleVisitor) VisitAim(aimCtx antlr.ParseTree, dCtx typedef.DataC
default:
}
if !flag {
a.errorCallback(node, "invalid condition context type")
a.errorCallback(node, "invalid aim context type")
return
}
// assignment data context and visit target