at operator return -1 when fails in lists and arrays; insert operators (<< and >>) changes che container if it is a variable

This commit is contained in:
2026-07-16 07:25:15 +02:00
parent 8c55f4ac4b
commit 2f616f349b
11 changed files with 105 additions and 60 deletions
+2 -2
View File
@@ -123,7 +123,7 @@ func intFunc(ctx kern.ExprContext, name string, args map[string]any) (result any
return
}
func decFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
func floatFunc(ctx kern.ExprContext, name string, args map[string]any) (result any, err error) {
switch v := args[kern.ParamValue].(type) {
case int64:
result = float64(v)
@@ -318,7 +318,7 @@ func ImportBuiltinsFuncs(ctx kern.ExprContext) {
ctx.RegisterFunc("bool", kern.NewGolangFunctor(boolFunc), kern.TypeBoolean, anyParams)
ctx.RegisterFunc("int", kern.NewGolangFunctor(intFunc), kern.TypeInt, anyParams)
ctx.RegisterFunc("dec", kern.NewGolangFunctor(decFunc), kern.TypeFloat, anyParams)
ctx.RegisterFunc("float", kern.NewGolangFunctor(floatFunc), kern.TypeFloat, anyParams)
ctx.RegisterFunc("string", kern.NewGolangFunctor(stringFunc), kern.TypeString, anyParams)
ctx.RegisterFunc("fract", kern.NewGolangFunctor(fractFunc), kern.TypeFraction, []kern.ExprFuncParam{
kern.NewFuncParam(kern.ParamValue),
+6 -1
View File
@@ -15,7 +15,12 @@ type Term interface {
GetChildCount() (count int)
GetChild(index int) Term
GetChildSource(index int) string
Compute(ctx ExprContext) (result any, err error)
GetLeftChild() (c Term)
GetRightChild() (c Term)
IsAssign() bool
IsVar() bool
Compute(ctx ExprContext) (result any, err error)
EvalInfix(ctx ExprContext) (leftValue, rightValue any, err error)
Errorf(template string, args ...any) (err error)
ErrIncompatibleTypes(leftValue, rightValue any) error
}
+4 -1
View File
@@ -36,6 +36,7 @@ func evalAt(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
return
}
v = int64(-1) // default value if not found
if array.IsArray(rightValue) {
a, _ := rightValue.(*array.ArrayType)
if index := a.IndexDeepSameCmp(leftValue); index >= 0 {
@@ -45,14 +46,16 @@ func evalAt(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
dict, _ := rightValue.(*dict.DictType)
if k, exists := dict.FindKey(leftValue); exists {
v = k
} else {
v = nil
}
} else if list.IsLinkedList(rightValue) {
ls, _ := rightValue.(*list.LinkedList)
if index := ls.Index(leftValue); index >= 0 {
v = index
}
} else {
v = nil
err = opTerm.ErrIncompatibleTypes(leftValue, rightValue)
}
return
+10 -20
View File
@@ -33,7 +33,7 @@ func newAppendTerm(tk *scan.Token) (inst *scan.Term) {
}
}
func prependToList(opTerm *scan.Term, leftValue, rightValue any) (result any, err error) {
func prependToList(opTerm kern.Term, leftValue, rightValue any) (result any, err error) {
if a, ok := rightValue.(*array.ArrayType); ok {
var it kern.Iterator
if it, ok = leftValue.(kern.Iterator); !ok {
@@ -53,6 +53,10 @@ func prependToList(opTerm *scan.Term, leftValue, rightValue any) (result any, er
for _, item := range *a {
newArray = append(newArray, item)
}
if opTerm.GetRightChild().IsVar() {
// Update the original array if the right operand is a variable
*a = newArray
}
result = &newArray
} else if ll, ok := rightValue.(*list.LinkedList); ok {
var it kern.Iterator
@@ -78,7 +82,7 @@ func evalPrepend(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
return
}
func appendToList(opTerm *scan.Term, leftValue, rightValue any) (result any, err error) {
func appendToList(opTerm kern.Term, leftValue, rightValue any) (result any, err error) {
if a, ok := leftValue.(*array.ArrayType); ok {
var it kern.Iterator
if it, ok = rightValue.(kern.Iterator); !ok {
@@ -98,6 +102,10 @@ func appendToList(opTerm *scan.Term, leftValue, rightValue any) (result any, err
for node := ls.FirstNode(); node != nil; node = node.Next() {
newArray = append(newArray, node.Data())
}
if opTerm.GetLeftChild().IsVar() {
// Update the original array if the left operand is a variable
*a = newArray
}
result = &newArray
} else if ll, ok := leftValue.(*list.LinkedList); ok {
var it kern.Iterator
@@ -124,24 +132,6 @@ func evalAppend(ctx kern.ExprContext, opTerm *scan.Term) (v any, err error) {
return
}
// // func evalAssignAppend(ctx ExprContext, self *term) (v any, err error) {
// // var leftValue, rightValue any
// // if leftValue, rightValue, err = self.evalInfix(ctx); err != nil {
// // return
// // }
// // if IsArray(leftValue) {
// // list, _ := leftValue.(*ListType)
// // newList := append(*list, rightValue)
// // v = &newList
// // if
// // } else {
// // err = self.errIncompatibleTypes(leftValue, rightValue)
// // }
// // return
// // }
// init
func init() {
scan.RegisterTermConstructor(scan.SymPlusGreater, newPrependTerm)
+22
View File
@@ -186,10 +186,32 @@ func (t *Term) GetChildSource(index int) (s string) {
return
}
func (t *Term) GetLeftChild() (c kern.Term) {
if t.Position == PosInfix && len(t.Children) > 0 {
c = t.Children[0]
}
return
}
func (t *Term) GetRightChild() (c kern.Term) {
if t.Position == PosInfix && len(t.Children) > 1 {
c = t.Children[1]
}
return
}
func (t *Term) IsAssign() bool {
return t.Symbol() == SymEqual
}
func (t *Term) IsVar() bool {
return t.Symbol() == SymVariable
}
// func (t *Term) IsFunc() bool {
// return t.Symbol() == SymFunction
// }
func (t *Term) Compute(ctx kern.ExprContext) (v any, err error) {
if t.EvalFunc == nil {
err = t.Errorf("undefined eval-func for %q term", t.Source())
+22 -24
View File
@@ -25,8 +25,8 @@ func TestArray(t *testing.T) {
/* 9 */ {`builtin "math.arith"; mul([1,4,3.0,2])`, float64(24.0), nil},
/* 10 */ {`builtin "math.arith"; add([1,"hello"])`, nil, `add(): param nr 2 (2 in 1) has wrong type string, number expected`},
/* 11 */ {`[a=1,b=2,c=3] but a+b+c`, int64(6), nil},
/* 12 */ {`[1,2,3] <+ 2+2`, array.NewArrayA(int64(1), int64(2), int64(3), int64(4)), nil},
/* 13 */ {`2-1 +> [2,3]`, array.NewArrayA(int64(1), int64(2), int64(3)), nil},
/* 12 */ {`[1,2,3] <+ 2+2`, array.ArrayFromIntsA(1, 2, 3, 4), nil},
/* 13 */ {`2-1 +> [2,3]`, array.ArrayFromIntsA(1, 2, 3), nil},
/* 14 */ {`[1,2,3][1]`, int64(2), nil},
/* 15 */ {`ls=[1,2,3] but ls[1]`, int64(2), nil},
/* 16 */ {`ls=[1,2,3] but ls[-1]`, int64(3), nil},
@@ -41,31 +41,26 @@ func TestArray(t *testing.T) {
/* 25 */ {`["a","b","c","d"][1,1]`, nil, `[1:19] one index only is allowed`},
/* 26 */ {`[0,1,2,3,4][:]`, array.NewArrayA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil},
/* 27 */ {`["a", "b", "c"] <+ ;`, nil, `[1:18] infix operator "<+" requires two non-nil operands, got 1`},
/* 28 */ {`2 << 3;`, int64(16), nil},
/* 29 */ {`but +> ["a", "b", "c"]`, nil, `[1:6] infix operator "+>" requires two non-nil operands, got 0`},
/* 30 */ {`2 >> 3;`, int64(0), nil},
/* 31 */ {`a=[1,2]; a<+3`, array.NewArrayA(int64(1), int64(2), int64(3)), nil},
/* 32 */ {`a=[1,2]; 5+>a`, array.NewArrayA(int64(5), int64(1), int64(2)), nil},
/* 33 */ {`L=[1,2]; L[0]=9; L`, array.NewArrayA(int64(9), int64(2)), nil},
/* 34 */ {`L=[1,2]; L[5]=9; L`, nil, `index 5 out of bounds (0, 1)`},
/* 35 */ {`L=[1,2]; L[]=9; L`, nil, `[1:12] index/key specification expected, got [] [array]`},
/* 36 */ {`L=[1,2]; L[nil]=9;`, nil, `[1:12] index/key is nil`},
/* 37 */ {`[0,1,2,3,4][2:3]`, array.NewArrayA(int64(2)), nil},
/* 38 */ {`[0,1,2,3,4][3:-1]`, array.NewArrayA(int64(3)), nil},
/* 30 */ {`[0,1,2,3,4][-3:-1]`, array.NewArrayA(int64(2), int64(3)), nil},
/* 40 */ {`[0,1,2,3,4][0:]`, array.NewArrayA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil},
/* 41 */ {`[0] << $([1,2,3,4])`, array.NewArrayA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil},
/* 42 */ {`L=[]; [1] >> L; L`, array.NewArrayA(), nil},
/* 43 */ {`L=[]; L << [1]; L`, array.NewArrayA(), nil},
/* 44 */ {`2 IN [1,2,3]`, true, nil},
/* 45 */ {`2 AT [1,2,3]`, int64(1), nil},
/* 46 */ {`4 AT [1,2,3]`, int64(-1), nil},
/* 28 */ {`but +> ["a", "b", "c"]`, nil, `[1:6] infix operator "+>" requires two non-nil operands, got 0`},
/* 29 */ {`a=[1,2]; a<+3`, array.NewArrayA(int64(1), int64(2), int64(3)), nil},
/* 30 */ {`a=[1,2]; 5+>a`, array.NewArrayA(int64(5), int64(1), int64(2)), nil},
/* 31 */ {`L=[1,2]; L[0]=9; L`, array.NewArrayA(int64(9), int64(2)), nil},
/* 32 */ {`L=[1,2]; L[5]=9; L`, nil, `index 5 out of bounds (0, 1)`},
/* 33 */ {`L=[1,2]; L[]=9; L`, nil, `[1:12] index/key specification expected, got [] [array]`},
/* 34 */ {`L=[1,2]; L[nil]=9;`, nil, `[1:12] index/key is nil`},
/* 35 */ {`[0,1,2,3,4][2:3]`, array.NewArrayA(int64(2)), nil},
/* 36 */ {`[0,1,2,3,4][3:-1]`, array.NewArrayA(int64(3)), nil},
/* 37 */ {`[0,1,2,3,4][-3:-1]`, array.NewArrayA(int64(2), int64(3)), nil},
/* 38 */ {`[0,1,2,3,4][0:]`, array.NewArrayA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil},
/* 39 */ {`2 IN [1,2,3]`, true, nil},
/* 40 */ {`2 AT [1,2,3]`, int64(1), nil},
/* 41 */ {`4 AT [1,2,3]`, int64(-1), nil},
// /* 44 */ {`[0,1,2,3,4][2:3]`, kern.NewListA(int64(20)), nil},
}
// t.Setenv("EXPR_PATH", ".")
// runTestSuiteSpec(t, section, inputs, 44)
// RunTestSuiteSpec(t, section, inputs, 43)
RunTestSuite(t, section, inputs)
}
@@ -82,11 +77,14 @@ func TestArrayInsert(t *testing.T) {
/* 8 */ {`$([]) >> ["a", "b"]`, array.NewArrayA("a", "b"), nil},
/* 9 */ {`["a", "b"] << $([1,2,3])`, array.NewArrayA("a", "b", int64(1), int64(2), int64(3)), nil},
/* 10 */ {`L=["a", "b"]; L << $([1,2,3])`, array.NewArrayA("a", "b", int64(1), int64(2), int64(3)), nil},
/* 11 */ {`L=["a", "b"]; L << $([1,2,3]); L`, array.NewArrayA("a", "b"), nil},
/* 11 */ {`L=["a", "b"]; L << $([1,2,3]); L`, array.NewArrayA("a", "b", int64(1), int64(2), int64(3)), nil},
/* 12 */ {`L << $([1,2,3])`, nil, `undefined variable or function "L"`},
/* 13 */ {`[0] << $([1,2,3,4])`, array.NewArrayA(int64(0), int64(1), int64(2), int64(3), int64(4)), nil},
/* 14 */ {`L=[]; [1] >> L; L`, array.NewArrayA(array.ArrayFromIntsA(1)), nil},
/* 15 */ {`L=[]; L << [1]; L`, array.NewArrayA(array.ArrayFromIntsA(1)), nil},
}
// runTestSuiteSpec(t, section, inputs, 9)
// RunTestSuiteSpec(t, section, inputs, 14)
RunTestSuite(t, section, inputs)
}
+10 -10
View File
@@ -40,13 +40,13 @@ func TestFuncBase(t *testing.T) {
/* 23 */ {`fract("1.21(3)")`, fract.NewFraction(91, 75), nil},
/* 24 */ {`fract(1.21(3))`, fract.NewFraction(91, 75), nil},
/* 25 */ {`fract(1.21)`, fract.NewFraction(121, 100), nil},
/* 26 */ {`dec(2)`, float64(2), nil},
/* 27 */ {`dec(2.0)`, float64(2), nil},
/* 28 */ {`dec("2.0")`, float64(2), nil},
/* 29 */ {`dec(true)`, float64(1), nil},
/* 30 */ {`dec(true")`, nil, "[1:11] expected one of `,`, `)`, got `\"`"},
/* 31 */ {`dec()`, nil, `dec(): too few params -- expected 1, got 0`},
/* 32 */ {`dec(1,2,3)`, nil, `dec(): too many params -- expected 1, got 3`},
/* 26 */ {`float(2)`, float64(2), nil},
/* 27 */ {`float(2.0)`, float64(2), nil},
/* 28 */ {`float("2.0")`, float64(2), nil},
/* 29 */ {`float(true)`, float64(1), nil},
/* 30 */ {`float(true")`, nil, "[1:13] expected one of `,`, `)`, got `\"`"},
/* 31 */ {`float()`, nil, `float(): too few params -- expected 1, got 0`},
/* 32 */ {`float(1,2,3)`, nil, `float(): too many params -- expected 1, got 3`},
/* 33 */ {`isBool(false)`, true, nil},
/* 34 */ {`fract(1:2)`, fract.NewFraction(1, 2), nil},
/* 35 */ {`fract(12,2)`, fract.NewFraction(6, 1), nil},
@@ -59,9 +59,9 @@ func TestFuncBase(t *testing.T) {
/* 42 */ {`bool([])`, false, nil},
/* 43 */ {`bool({})`, false, nil},
/* 44 */ {`bool({1:"one"})`, true, nil},
/* 45 */ {`dec(false)`, float64(0), nil},
/* 46 */ {`dec(1:2)`, float64(0.5), nil},
/* 47 */ {`dec([1])`, nil, `dec(): can't convert array to float`},
/* 45 */ {`float(false)`, float64(0), nil},
/* 46 */ {`float(1:2)`, float64(0.5), nil},
/* 47 */ {`float([1])`, nil, `float(): can't convert array to float`},
/* 48 */ {`eval("a=3"); a`, int64(3), nil},
/* 49 */ {`int(5:2)`, int64(2), nil},
+2 -2
View File
@@ -38,10 +38,10 @@ func TestLinkedInsert(t *testing.T) {
section := "LinkedList-Insert"
inputs := []inputType{
/* 1 */ {`[<>] << 1`, list.NewLinkedListA(1), nil},
/* 2 */ {`[<>] << [1,2]`, list.NewLinkedListA(array.NewArrayA(int64(1), int64(2))), nil},
/* 2 */ {`[<>] << [1,2]`, list.NewLinkedListA(array.ArrayFromIntsA(1, 2)), nil},
/* 3 */ {`[<>] << [<1,2>]`, list.NewLinkedListA(list.NewLinkedListA(1, 2)), nil},
/* 4 */ {`1 >> [<>]`, list.NewLinkedListA(1), nil},
/* 5 */ {`[1,2] >> [<>]`, list.NewLinkedListA(array.NewArrayA(int64(1), int64(2))), nil},
/* 5 */ {`[1,2] >> [<>]`, list.NewLinkedListA(array.ArrayFromIntsA(1, 2)), nil},
/* 6 */ {`[<1,2>] >> [<>]`, list.NewLinkedListA(list.NewLinkedListA(1, 2)), nil},
/* 7 */ {`$([1,2]) >> [<>]`, list.NewLinkedListA(1, 2), nil},
/* 8 */ {`$([<1,2>]) >> [<>]`, list.NewLinkedListA(1, 2), nil},
+2
View File
@@ -42,6 +42,8 @@ func TestOperator(t *testing.T) {
/* 26 */ {`a="1"; --a`, nil, `[1:9] prefix/postfix operator "--" does not support operand '1' [string]`},
/* 27 */ {`a="1"; a++`, nil, `[1:10] prefix/postfix operator "++" does not support operand '1' [string]`},
/* 28 */ {`a="1"; a--`, nil, `[1:10] prefix/postfix operator "--" does not support operand '1' [string]`},
/* 29 */ {`2 << 3;`, int64(16), nil},
/* 30 */ {`2 >> 3;`, int64(0), nil},
}
// t.Setenv("EXPR_PATH", ".")
+12
View File
@@ -51,6 +51,18 @@ func ArrayFromStrings(stringSlice []string) (aRef *ArrayType) {
return
}
func ArrayFromIntsA(ints ...int) (aRef *ArrayType) {
return ArrayFromInts(ints)
}
func ArrayFromInts(intSlice []int) (aRef *ArrayType) {
aRef = MakeArray(len(intSlice), 0)
for i, s := range intSlice {
(*aRef)[i] = int64(s)
}
return
}
func (aRef *ArrayType) ToString(opt kern.FmtOpt) (s string) {
indent := kern.GetFormatIndent(opt)
flags := kern.GetFormatFlags(opt)
+13
View File
@@ -141,6 +141,19 @@ func (ls *LinkedList) Last() (data any, err error) {
return
}
// func (ls *LinkedList) Reverse() *ListNode {
// var prev *ListNode
// for current := ls.first; current != nil; {
// succ := current.next
// prev = succ.next
// succ.next = current
// current = prev
// }
// ls.first, ls.last = ls.last, ls.first
// return ls.first
// }
func (ls *LinkedList) NodeAt(index64 int64) (node *ListNode, err error) {
index := int(index64)
if ls.count == 0 {