mirror of
https://github.com/bytedance/arishem.git
synced 2025-12-24 11:30:57 +08:00
support aim walk
Change-Id: I9014e1edadd22fbeb17bf3d4473fed47b784134a
This commit is contained in:
@@ -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...)
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user