Compare commits
2 Commits
4b25a07699
...
v0.15.0
| Author | SHA1 | Date | |
|---|---|---|---|
| f41ea96d17 | |||
| d84e690ef3 |
@@ -34,6 +34,7 @@ type ExprFunc interface {
|
||||
// ----Expression Context
|
||||
type ExprContext interface {
|
||||
Clone() ExprContext
|
||||
Merge(ctx ExprContext)
|
||||
GetVar(varName string) (value any, exists bool)
|
||||
SetVar(varName string, value any)
|
||||
UnsafeSetVar(varName string, value any)
|
||||
|
||||
+9
-4
@@ -34,7 +34,7 @@ func (functor *baseFunctor) GetFunc() ExprFunc {
|
||||
return functor.info
|
||||
}
|
||||
|
||||
// ---- Linking with the functions of Go
|
||||
// ---- Linking with Go functions
|
||||
type golangFunctor struct {
|
||||
baseFunctor
|
||||
f FuncTemplate
|
||||
@@ -48,18 +48,23 @@ func (functor *golangFunctor) Invoke(ctx ExprContext, name string, args []any) (
|
||||
return functor.f(ctx, name, args)
|
||||
}
|
||||
|
||||
// ---- Linking with the functions of Expr
|
||||
// ---- Linking with Expr functions
|
||||
type exprFunctor struct {
|
||||
baseFunctor
|
||||
params []string
|
||||
expr Expr
|
||||
defCtx ExprContext
|
||||
}
|
||||
|
||||
func newExprFunctor(e Expr, params []string) *exprFunctor {
|
||||
return &exprFunctor{expr: e, params: params}
|
||||
func newExprFunctor(e Expr, params []string, ctx ExprContext) *exprFunctor {
|
||||
return &exprFunctor{expr: e, params: params, defCtx: ctx}
|
||||
}
|
||||
|
||||
func (functor *exprFunctor) Invoke(ctx ExprContext, name string, args []any) (result any, err error) {
|
||||
if functor.defCtx != nil {
|
||||
ctx.Merge(functor.defCtx)
|
||||
}
|
||||
|
||||
for i, p := range functor.params {
|
||||
if i < len(args) {
|
||||
arg := args[i]
|
||||
|
||||
+55
-8
@@ -85,7 +85,7 @@ func (ls *ListType) contains(t *ListType) (answer bool) {
|
||||
if len(*ls) >= len(*t) {
|
||||
answer = true
|
||||
for _, item := range *t {
|
||||
if answer = ls.indexDeepCmp(item) >= 0; !answer {
|
||||
if answer = ls.indexDeepSameCmp(item) >= 0; !answer {
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -93,10 +93,57 @@ func (ls *ListType) contains(t *ListType) (answer bool) {
|
||||
return
|
||||
}
|
||||
|
||||
// func equal(a,b *ListType) (eq bool) {
|
||||
// if len(*a) == len(*b) {
|
||||
// eq = true
|
||||
// for i, v := range
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
func (list *ListType) indexDeepSameCmp(target any) (index int) {
|
||||
var eq bool
|
||||
var err error
|
||||
index = -1
|
||||
for i, item := range *list {
|
||||
if eq, err = deepSame(item, target, sameContent); err != nil {
|
||||
break
|
||||
} else if eq {
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func sameContent(a, b any) (same bool, err error) {
|
||||
la, _ := a.(*ListType)
|
||||
lb, _ := b.(*ListType)
|
||||
if len(*la) == len(*lb) {
|
||||
same = true
|
||||
for _, item := range *la {
|
||||
if pos := lb.indexDeepSameCmp(item); pos < 0 {
|
||||
same = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func deepSame(a, b any, deepCmp deepFuncTemplate) (eq bool, err error) {
|
||||
if isNumOrFract(a) && isNumOrFract(b) {
|
||||
if IsNumber(a) && IsNumber(b) {
|
||||
if IsInteger(a) && IsInteger(b) {
|
||||
li, _ := a.(int64)
|
||||
ri, _ := b.(int64)
|
||||
eq = li == ri
|
||||
} else {
|
||||
eq = numAsFloat(a) == numAsFloat(b)
|
||||
}
|
||||
} else {
|
||||
var cmp int
|
||||
if cmp, err = cmpAnyFract(a, b); err == nil {
|
||||
eq = cmp == 0
|
||||
}
|
||||
}
|
||||
} else if deepCmp != nil && IsList(a) && IsList(b) {
|
||||
eq, err = deepCmp(a, b)
|
||||
} else {
|
||||
eq = reflect.DeepEqual(a, b)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
+1
-5
@@ -108,11 +108,7 @@ func evalFuncDef(ctx ExprContext, self *term) (v any, err error) {
|
||||
for _, param := range self.children {
|
||||
paramList = append(paramList, param.source())
|
||||
}
|
||||
v = newExprFunctor(expr, paramList)
|
||||
// v = &funcDefFunctor{
|
||||
// params: paramList,
|
||||
// expr: expr,
|
||||
// }
|
||||
v = newExprFunctor(expr, paramList, ctx)
|
||||
} else {
|
||||
err = errors.New("invalid function definition: the body specification must be an expression")
|
||||
}
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ func evalIn(ctx ExprContext, self *term) (v any, err error) {
|
||||
|
||||
if IsList(rightValue) {
|
||||
list, _ := rightValue.(*ListType)
|
||||
v = list.indexDeepCmp(leftValue) >= 0
|
||||
v = list.indexDeepSameCmp(leftValue) >= 0
|
||||
} else if IsDict(rightValue) {
|
||||
dict, _ := rightValue.(*DictType)
|
||||
v = dict.hasKey(leftValue)
|
||||
|
||||
+8
-26
@@ -18,7 +18,9 @@ func newEqualTerm(tk *Token) (inst *term) {
|
||||
}
|
||||
}
|
||||
|
||||
func equals(a, b any) (eq bool, err error) {
|
||||
type deepFuncTemplate func(a, b any) (eq bool, err error)
|
||||
|
||||
func equals(a, b any, deepCmp deepFuncTemplate) (eq bool, err error) {
|
||||
if isNumOrFract(a) && isNumOrFract(b) {
|
||||
if IsNumber(a) && IsNumber(b) {
|
||||
if IsInteger(a) && IsInteger(b) {
|
||||
@@ -34,6 +36,8 @@ func equals(a, b any) (eq bool, err error) {
|
||||
eq = cmp == 0
|
||||
}
|
||||
}
|
||||
} else if deepCmp != nil && IsList(a) && IsList(b) {
|
||||
eq, err = deepCmp(a, b)
|
||||
} else {
|
||||
eq = reflect.DeepEqual(a, b)
|
||||
}
|
||||
@@ -48,7 +52,7 @@ func evalEqual(ctx ExprContext, self *term) (v any, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
v, err = equals(leftValue, rightValue)
|
||||
v, err = equals(leftValue, rightValue, nil)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -108,15 +112,7 @@ func lessThan(self *term, a, b any) (isLess bool, err error) {
|
||||
} else if IsList(a) && IsList(b) {
|
||||
aList, _ := a.(*ListType)
|
||||
bList, _ := b.(*ListType)
|
||||
isLess = len(*aList) < len(*bList)
|
||||
if isLess {
|
||||
for _, item := range *aList {
|
||||
if bList.indexDeepCmp(item) < 0 {
|
||||
isLess = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
isLess = len(*aList) < len(*bList) && bList.contains(aList)
|
||||
} else {
|
||||
err = self.errIncompatibleTypes(a, b)
|
||||
}
|
||||
@@ -145,27 +141,13 @@ func newLessEqualTerm(tk *Token) (inst *term) {
|
||||
}
|
||||
}
|
||||
|
||||
func sameContent(a, b any) (same bool, err error) {
|
||||
la, _ := a.(*ListType)
|
||||
lb, _ := b.(*ListType)
|
||||
if len(*la) == len(*lb) {
|
||||
same = true
|
||||
for i, item := range *la {
|
||||
if same, err = equals(item, (*lb)[i]); err != nil || !same {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func lessThanOrEqual(self *term, a, b any) (isLessEq bool, err error) {
|
||||
if isLessEq, err = lessThan(self, a, b); err == nil {
|
||||
if !isLessEq {
|
||||
if IsList(a) && IsList(b) {
|
||||
isLessEq, err = sameContent(a, b)
|
||||
} else {
|
||||
isLessEq, err = equals(a, b)
|
||||
isLessEq, err = equals(a, b, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-7
@@ -12,29 +12,40 @@ import (
|
||||
|
||||
type SimpleStore struct {
|
||||
varStore map[string]any
|
||||
funcStore map[string]*funcInfo
|
||||
funcStore map[string]ExprFunc
|
||||
}
|
||||
|
||||
func NewSimpleStore() *SimpleStore {
|
||||
ctx := &SimpleStore{
|
||||
varStore: make(map[string]any),
|
||||
funcStore: make(map[string]*funcInfo),
|
||||
funcStore: make(map[string]ExprFunc),
|
||||
}
|
||||
//ImportBuiltinsFuncs(ctx)
|
||||
return ctx
|
||||
}
|
||||
|
||||
func filterRefName(name string) bool { return name[0] != '@' }
|
||||
func filterPrivName(name string) bool { return name[0] != '_' }
|
||||
|
||||
func (ctx *SimpleStore) Clone() ExprContext {
|
||||
return &SimpleStore{
|
||||
varStore: CloneFilteredMap(ctx.varStore, func(name string) bool { return name[0] != '@' }),
|
||||
funcStore: CloneFilteredMap(ctx.funcStore, func(name string) bool { return name[0] != '@' }),
|
||||
varStore: CloneFilteredMap(ctx.varStore, filterRefName),
|
||||
funcStore: CloneFilteredMap(ctx.funcStore, filterRefName),
|
||||
}
|
||||
}
|
||||
|
||||
func (ctx *SimpleStore) Merge(src ExprContext) {
|
||||
for _, name := range src.EnumVars(filterRefName) {
|
||||
ctx.varStore[name], _ = src.GetVar(name)
|
||||
}
|
||||
for _, name := range src.EnumFuncs(filterRefName) {
|
||||
ctx.funcStore[name], _ = src.GetFuncInfo(name)
|
||||
}
|
||||
}
|
||||
|
||||
func varsCtxToBuilder(sb *strings.Builder, ctx ExprContext, indent int) {
|
||||
sb.WriteString("vars: {\n")
|
||||
first := true
|
||||
for _, name := range ctx.EnumVars(func(name string) bool { return name[0] != '_' }) {
|
||||
for _, name := range ctx.EnumVars(filterPrivName) {
|
||||
if first {
|
||||
first = false
|
||||
} else {
|
||||
@@ -164,7 +175,7 @@ func (ctx *SimpleStore) EnumFuncs(acceptor func(name string) (accept bool)) (fun
|
||||
|
||||
func (ctx *SimpleStore) Call(name string, args []any) (result any, err error) {
|
||||
if info, exists := ctx.funcStore[name]; exists {
|
||||
functor := info.functor
|
||||
functor := info.Functor()
|
||||
result, err = functor.Invoke(ctx, name, args)
|
||||
} else {
|
||||
err = fmt.Errorf("unknown function %s()", name)
|
||||
|
||||
@@ -40,10 +40,13 @@ func TestRelational(t *testing.T) {
|
||||
/* 27 */ {`[1,2,3] > [9]`, false, nil},
|
||||
/* 28 */ {`[1,2,3] >= [6]`, false, nil},
|
||||
/* 29 */ {`[1,2,3] >= [2,6]`, false, nil},
|
||||
/* 30 */ {`[1,[2,3],4] > [[3,2]]`, true, nil},
|
||||
/* 31 */ {`[1,[2,[3,4]],5] > [[[4,3],2]]`, true, nil},
|
||||
/* 32 */ {`[[4,3],2] IN [1,[2,[3,4]],5]`, true, nil},
|
||||
}
|
||||
|
||||
// t.Setenv("EXPR_PATH", ".")
|
||||
|
||||
// parserTestSpec(t, section, inputs, 27)
|
||||
// parserTestSpec(t, section, inputs, 31)
|
||||
parserTest(t, section, inputs)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user