The plus and minus operators now support lists for join and difference respectively
This commit is contained in:
parent
f540ec28e8
commit
85fb007a2b
@ -6,6 +6,7 @@ package expr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"slices"
|
||||||
)
|
)
|
||||||
|
|
||||||
//-------- plus term
|
//-------- plus term
|
||||||
@ -39,6 +40,23 @@ func evalPlus(ctx exprContext, self *term) (v any, err error) {
|
|||||||
rightInt, _ := rightValue.(int64)
|
rightInt, _ := rightValue.(int64)
|
||||||
v = leftInt + rightInt
|
v = leftInt + rightInt
|
||||||
}
|
}
|
||||||
|
} else if isList(leftValue) || isList(rightValue) {
|
||||||
|
var leftList, rightList []any
|
||||||
|
var ok bool
|
||||||
|
if leftList, ok = leftValue.([]any); !ok {
|
||||||
|
leftList = []any{leftValue}
|
||||||
|
}
|
||||||
|
if rightList, ok = rightValue.([]any); !ok {
|
||||||
|
rightList = []any{rightValue}
|
||||||
|
}
|
||||||
|
sumList := make([]any, 0, len(leftList)+len(rightList))
|
||||||
|
for _, item := range leftList {
|
||||||
|
sumList = append(sumList, item)
|
||||||
|
}
|
||||||
|
for _, item := range rightList {
|
||||||
|
sumList = append(sumList, item)
|
||||||
|
}
|
||||||
|
v = sumList
|
||||||
} else {
|
} else {
|
||||||
err = self.errIncompatibleTypes(leftValue, rightValue)
|
err = self.errIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
@ -74,6 +92,16 @@ func evalMinus(ctx exprContext, self *term) (v any, err error) {
|
|||||||
rightInt, _ := rightValue.(int64)
|
rightInt, _ := rightValue.(int64)
|
||||||
v = leftInt - rightInt
|
v = leftInt - rightInt
|
||||||
}
|
}
|
||||||
|
} else if isList(leftValue) && isList(rightValue) {
|
||||||
|
leftList, _ := leftValue.([]any)
|
||||||
|
rightList, _ := rightValue.([]any)
|
||||||
|
diffList := make([]any, 0, len(leftList)-len(rightList))
|
||||||
|
for _, item := range leftList {
|
||||||
|
if slices.Index(rightList, item) < 0 {
|
||||||
|
diffList = append(diffList, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v = diffList
|
||||||
} else {
|
} else {
|
||||||
err = self.errIncompatibleTypes(leftValue, rightValue)
|
err = self.errIncompatibleTypes(leftValue, rightValue)
|
||||||
}
|
}
|
||||||
|
@ -11,38 +11,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func addFunc(ctx exprContext, name string, args []any) (result any, err error) {
|
|
||||||
var sumAsFloat = false
|
|
||||||
var floatSum float64 = 0.0
|
|
||||||
var intSum int64 = 0
|
|
||||||
|
|
||||||
for i, v := range args {
|
|
||||||
if !isNumber(v) {
|
|
||||||
err = fmt.Errorf("add(): param nr %d has wrong type %T, number expected", i+1, v)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if !sumAsFloat && isFloat(v) {
|
|
||||||
sumAsFloat = true
|
|
||||||
floatSum = float64(intSum)
|
|
||||||
}
|
|
||||||
if sumAsFloat {
|
|
||||||
floatSum += numAsFloat(v)
|
|
||||||
} else {
|
|
||||||
iv, _ := v.(int64)
|
|
||||||
intSum += iv
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
if sumAsFloat {
|
|
||||||
result = floatSum
|
|
||||||
} else {
|
|
||||||
result = intSum
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestParser(t *testing.T) {
|
func TestParser(t *testing.T) {
|
||||||
type inputType struct {
|
type inputType struct {
|
||||||
source string
|
source string
|
||||||
@ -54,7 +22,8 @@ func TestParser(t *testing.T) {
|
|||||||
ctx := NewSimpleFuncStore()
|
ctx := NewSimpleFuncStore()
|
||||||
ctx.SetValue("var1", int64(123))
|
ctx.SetValue("var1", int64(123))
|
||||||
ctx.SetValue("var2", "abc")
|
ctx.SetValue("var2", "abc")
|
||||||
ctx.addFunc("add", addFunc)
|
// ctx.addFunc("add", addFunc)
|
||||||
|
importMathFuncs(ctx)
|
||||||
|
|
||||||
// inputs1 := []inputType{
|
// inputs1 := []inputType{
|
||||||
// {`add(1,2,3)`, int64(6), nil},
|
// {`add(1,2,3)`, int64(6), nil},
|
||||||
@ -94,10 +63,10 @@ func TestParser(t *testing.T) {
|
|||||||
/* 31 */ {"(1+1)*5", int64(10), nil},
|
/* 31 */ {"(1+1)*5", int64(10), nil},
|
||||||
/* 32 */ {"200 / (1+1) - 1", int64(99), nil},
|
/* 32 */ {"200 / (1+1) - 1", int64(99), nil},
|
||||||
/* 33 */ {`add(1,2,3)`, int64(6), nil},
|
/* 33 */ {`add(1,2,3)`, int64(6), nil},
|
||||||
/* 34 */ {`mul(1,2,3)`, nil, errors.New(`unknown function "mul"`)},
|
/* 34 */ {`mulX(1,2,3)`, nil, errors.New(`unknown function mulX()`)},
|
||||||
/* 35 */ {`add(1+4,3+2,5*(3-2))`, int64(15), nil},
|
/* 35 */ {`add(1+4,3+2,5*(3-2))`, int64(15), nil},
|
||||||
/* 36 */ {`add(add(1+4),3+2,5*(3-2))`, int64(15), nil},
|
/* 36 */ {`add(add(1+4),3+2,5*(3-2))`, int64(15), nil},
|
||||||
/* 37 */ {`add(add(1+4),/*3+2,*/5*(3-2))`, int64(10), nil},
|
/* 37 */ {`add(add(1,4),/*3+2,*/5*(3-2))`, int64(10), nil},
|
||||||
/* 38 */ {`1+(1+(1+(1)+1)+1)+1`, int64(7), nil},
|
/* 38 */ {`1+(1+(1+(1)+1)+1)+1`, int64(7), nil},
|
||||||
/* 39 */ {`(((1)))`, int64(1), nil},
|
/* 39 */ {`(((1)))`, int64(1), nil},
|
||||||
/* 40 */ {`"uno_" + var2`, `uno_abc`, nil},
|
/* 40 */ {`"uno_" + var2`, `uno_abc`, nil},
|
||||||
@ -209,7 +178,8 @@ func TestListParser(t *testing.T) {
|
|||||||
ctx := NewSimpleFuncStore()
|
ctx := NewSimpleFuncStore()
|
||||||
ctx.SetValue("var1", int64(123))
|
ctx.SetValue("var1", int64(123))
|
||||||
ctx.SetValue("var2", "abc")
|
ctx.SetValue("var2", "abc")
|
||||||
ctx.addFunc("add", addFunc)
|
// ctx.addFunc("add", addFunc)
|
||||||
|
importMathFuncs(ctx)
|
||||||
|
|
||||||
// inputs1 := []inputType{
|
// inputs1 := []inputType{
|
||||||
// {`add(1,2,3)`, int64(6), nil},
|
// {`add(1,2,3)`, int64(6), nil},
|
||||||
@ -220,6 +190,14 @@ func TestListParser(t *testing.T) {
|
|||||||
/* 2 */ {`[1,2,3]`, []any{int64(1), int64(2), int64(3)}, nil},
|
/* 2 */ {`[1,2,3]`, []any{int64(1), int64(2), int64(3)}, nil},
|
||||||
/* 3 */ {`[1,2,"hello"]`, []any{int64(1), int64(2), "hello"}, nil},
|
/* 3 */ {`[1,2,"hello"]`, []any{int64(1), int64(2), "hello"}, nil},
|
||||||
/* 4 */ {`[1+2, not true, "hello"]`, []any{int64(3), false, "hello"}, nil},
|
/* 4 */ {`[1+2, not true, "hello"]`, []any{int64(3), false, "hello"}, nil},
|
||||||
|
/* 5 */ {`[1,2]+[3]`, []any{int64(1), int64(2), int64(3)}, nil},
|
||||||
|
/* 6 */ {`[1,4,3,2]-[3]`, []any{int64(1), int64(4), int64(2)}, nil},
|
||||||
|
/* 7 */ {`add([1,4,3,2])`, int64(10), nil},
|
||||||
|
/* 8 */ {`add([1,[2,2],3,2])`, int64(10), nil},
|
||||||
|
/* 9 */ {`mul([1,4,3.0,2])`, float64(24.0), nil},
|
||||||
|
/* 10 */ {`add([1,"hello"])`, nil, errors.New(`add(): param nr 2 has wrong type string, number expected`)},
|
||||||
|
// /* 8 */ {`[int(x)|x=csv("test.csv",1,all(),1)]`, []any{int64(10), int64(40), int64(20)}, nil},
|
||||||
|
// /* 9 */ {`sum(@[int(x)|x=csv("test.csv",1,all(),1)])`, []any{int64(10), int64(40), int64(20)}, nil},
|
||||||
}
|
}
|
||||||
|
|
||||||
succeeded := 0
|
succeeded := 0
|
||||||
@ -232,9 +210,9 @@ func TestListParser(t *testing.T) {
|
|||||||
var gotErr error
|
var gotErr error
|
||||||
|
|
||||||
if input.wantErr == nil {
|
if input.wantErr == nil {
|
||||||
t.Log(fmt.Sprintf("[+]Test nr %2d -- %q", i+1, input.source))
|
t.Log(fmt.Sprintf("[+]Test nr %2d -- %q --> %v", i+1, input.source, input.wantResult))
|
||||||
} else {
|
} else {
|
||||||
t.Log(fmt.Sprintf("[-]Test nr %2d -- %q", i+1, input.source))
|
t.Log(fmt.Sprintf("[-]Test nr %2d -- %q --> %v", i+1, input.source, input.wantResult))
|
||||||
}
|
}
|
||||||
|
|
||||||
r := strings.NewReader(input.source)
|
r := strings.NewReader(input.source)
|
||||||
|
Loading…
Reference in New Issue
Block a user